Guide
6 min read

WebSocket-Specific Checks to Run Before Rolling a Realtime App Deploy

Realtime apps pass an HTTP health check and still drop every live connection on deploy. The WebSocket-specific checks that catch it before your users do.

WebSocket-Specific Checks to Run Before Rolling a Realtime App Deploy

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 SIGTERM by 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 SIGTERM handling.
  • 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.

websockets
realtime
deployments
reverse-proxy
health-checks

From across the StoicSoft network

Hand-curated reads on the same topic from sister sites in the StoicSoft family.

Keep reading

Guide
8 min

Beginners need one exposure model before mixing tunnels, reverse proxies, VLANs, and Tailscale

Fresh self-hosting threads show beginners combining the right words without a safe operating model. One new self-hoster wants Minecraft, Jellyfin, Tailscale, maybe NAS/cloud storage, Nginx, Cloudflare tunnels or DDNS, Docker or VLANs, fail2ban, firewall…

Guide
8 min

Reverse-proxy success needs application-level proof, not just a working domain

Fresh Reddit threads show self-hosters getting past the first domain or certificate milestone, then discovering that the application path is still broken. One Nextcloud snap user can reach the main app through a Synology reverse proxy, but Collabora…

Guide
8 min

Self-hosted edge fixes need causal proof across mDNS, ACME, Caddy callbacks, and intermittent 404s

Fresh posts keep separating “the change worked once” from “the edge path is understood.” A Home Assistant user got IKEA Matter devices working after changing UniFi mDNS settings but still does not know why. A DevOps post says HAProxy ACME issuance worked…

Guide
7 min

Lost HTTPS After a Network Change? A SWAG and Let's Encrypt Recovery Checklist

Immich or Jellyfin loses HTTPS after an ISP change or a simple network move, and the SWAG logs are a wall of ACME errors. A recovery checklist that starts at DNS and ends at a renewed cert.

Guide
7 min

A Safer Reverse-Proxy Decision Tree for Self-Hosted Media Apps

Should Jellyfin and Immich be public behind a reverse proxy, private over a VPN, or both? A decision tree that weighs privacy, family access, and streaming bandwidth instead of guessing.

Guide
7 min

Traefik Migrations Keep Failing at the Edge Where Cloudflare and App Routing Meet

Moving to Traefik breaks in a predictable place: the seam between Cloudflare's edge and Traefik's routing — redirect loops, wrong client IPs, and certs that won't issue. How to fix the seam.