LFA study materials
LFA study resources

Instance Healthy After Reboot, Portal Unreachable

LFA · Put your knowledge to work in context.

All case studies

Instance Healthy After Reboot, Portal Unreachable

A team runs a small customer portal on one cloud VM (Ubuntu 22.04) with an automatically assigned public IPv4 address, not a reserved or static one. nginx terminates TLS on 443 and proxies to a Node.js process listening on 127.0.0.1:3000. Both nginx and the Node process were installed and started by hand over SSH; no systemd units were written and nothing was enabled at boot. The security group allows inbound 22 from the office /32 only and 443 from 0.0.0.0/0; the network ACL allows all traffic in both directions. The DNS A record portal.example.com points to 203.0.113.45. During a maintenance window an engineer reboots the instance from the provider console. Afterwards, browsers time out on https://portal.example.com and the engineer's SSH client times out connecting to 203.0.113.45. The provider reports the instance running and passing both system and instance status checks, and browser-based console access works.

1. In what order would you investigate, and what does working console access rule out?

Read the worked answer

Console access proves the instance is running, the OS booted, and credentials are not the problem. It rules out hypervisor failure, a failed boot, and lost SSH keys. It does not prove anything about networking, listeners, or the address the outside world should use.

Order:

  1. Look up the instance's current public IP in the provider console or API. Auto-assigned addresses are usually released on stop and a different one assigned on start. The engineer connects to the old literal 203.0.113.45 and times out; that single fact explains both the SSH and the HTTPS symptom simultaneously.
  2. From the serial console run ip -4 addr to confirm the internal address and ss -tlnp to see whether anything is listening on 443 and 3000.
  3. Only then examine security groups and ACLs. They are unchanged and the ACL allows all, so changing rules would be action without a hypothesis.

Reason about the error type: timeouts mean packets are going nowhere or being silently dropped, while connection refused means the host answered and nothing was listening. Both symptoms being timeouts, with unchanged firewall config, points at the destination address.

2. After the address problem is corrected, browsers now get 'connection refused' on port 443. Explain the cause and the fix, and distinguish it from a 502.

Read the worked answer

Refused means the packet reached the host and the host sent a TCP reset because nothing is bound to 443. nginx was started by hand and never enabled, so the reboot left it stopped. The reboot did not break nginx; it revealed that its running state was never persistent.

Fix by making both tiers supervised: write a unit for the Node service, for example ExecStart=/usr/bin/node /opt/portal/server.js, WorkingDirectory=/opt/portal, User=portal, EnvironmentFile=/etc/portal.env, Restart=always, After=network-online.target, then systemctl daemon-reload && systemctl enable --now portal. Enable the distribution's nginx unit with systemctl enable --now nginx. Verify in layers: ss -tlnp for 3000 and 443, curl -I http://127.0.0.1:3000 for the app, curl -kI https://127.0.0.1 for TLS and proxying, then test from outside.

The error taxonomy matters: refused means no listener; 502 means nginx is listening but cannot reach the upstream, which would point at the Node process, the proxy_pass address, or SELinux/AppArmor blocking the proxy connection.

3. What changes would make this deployment reproducible so a reboot cannot cause the same class of outage?

Read the worked answer

The root cause is that the running system existed only as a sequence of manual actions. Encode it: a cloud-init user-data script or a configuration-management role that installs packages, writes the systemd units and nginx site config, enables both services, and deploys the application artefact at a pinned version. Better still, bake a machine image so a replacement instance is identical by construction.

Separate addressing from the instance: attach a reserved static IP or put a load balancer with health checks in front so the DNS record never points at an address that can be reassigned. If DNS must follow the instance, keep the TTL low and automate the update.

Add external synthetic monitoring that requests the public URL every minute and alerts on failure, rather than relying on provider status checks that only test the hypervisor and guest agent. Practise the failure: reboot the instance in staging as a routine drill, and treat "survives reboot" as an acceptance criterion for any new service.