A realtime app — chat, collaborative editor, live dashboard, anything with a persistent connection — has a deploy failure mode that a normal HTTP health check completely misses. The new container answers GET /health with a 200, the rollout proceeds, and meanwhile every live WebSocket has been dropped, sticky routing is sending users to the wrong instance, or an idle-timeout is silently killing connections sixty seconds in. The app is "up" and the experience is broken. These are the WebSocket-specific checks to run before you roll.
Check 1: the proxy actually upgrades
The first thing to verify on any new edge config is that the WebSocket handshake completes end to end, not just that the HTTP page loads. The upgrade needs HTTP/1.1 and the Upgrade/Connection headers forwarded all the way through:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Test it directly (websocat wss://app.example.com/ws) rather than trusting that the page rendered. A frozen UI with a green health check is the signature of a missing upgrade.
Check 2: idle timeouts longer than your heartbeat
Proxies close "idle" connections, but a WebSocket can be legitimately quiet between messages. If proxy_read_timeout is shorter than your app's ping interval, connections drop on a timer. Set the proxy idle timeout comfortably above the app's heartbeat, and make sure the app sends heartbeats. This is the same targeted-timeout discipline reverse proxies need elsewhere — the related trap of a stale upstream causing intermittent 502s shows up here as random disconnects.
Check 3: sticky sessions if state is per-instance
If your realtime app keeps connection state in memory (rooms, presence) and you run more than one instance, a load balancer that round-robins WebSocket frames will scatter a user's messages across instances. Either:
- enable sticky sessions so a connection pins to one instance, or
- move shared state to Redis/a pub-sub backplane so any instance can serve any connection.
Pick one before you scale past a single instance — discovering it during a deploy is the worst time.
Check 4: graceful connection draining on rollout
A rolling deploy that kills the old container immediately severs every open socket at once. Clients reconnect in a thundering herd and the new instance gets slammed. Drain instead:
- Stop accepting new connections on the old instance, let existing ones finish or migrate, then retire it.
- Make sure the app handles
SIGTERMby closing sockets cleanly with a reconnect signal, not by hard-exiting.
Check 5: a rollback that actually restores connections
If the deploy goes wrong, rolling back the container isn't enough if the proxy config also changed. Keep the rollback atomic and rehearsed — a rollback playbook with alert context in one place is what turns "everyone got disconnected" into a 60-second recovery.
Preflight checklist
- WebSocket upgrade verified end to end (not just the HTTP page).
- Proxy idle timeout > app heartbeat interval; app sends heartbeats.
- Sticky sessions or a shared backplane decided before multi-instance.
- Graceful drain on rollout; clean
SIGTERMhandling. - Atomic, rehearsed rollback covering proxy config too.
HTTP health checks tell you the process started. For realtime apps, these five tell you the actual product still works.
From across the StoicSoft network
Hand-curated reads on the same topic from sister sites in the StoicSoft family.
