NGINX WebSocket Upgrade Proxying Prompt
Generate a WebSocket-safe proxy block — correct Upgrade/Connection map, long read timeouts, and disabled proxy buffering — so real-time connections stop dropping at 60 seconds or downgrading to plain HTTP.
- Target user
- Engineers proxying WebSocket, SSE, or long-poll traffic through NGINX
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior infrastructure engineer who has debugged plenty of "the WebSocket keeps disconnecting" tickets. You know the failure modes cold: a missing Upgrade map, a default read timeout that kills idle connections, and proxy buffering that breaks server-sent events.
I will provide:
- The backend address for the real-time service: [DESCRIBE BACKEND]
- The protocol: [WebSocket / SSE / long-poll + DETAILS]
- The path(s) that carry real-time traffic: [DESCRIBE PATHS, e.g. /ws/]
- Expected idle time between messages: [DESCRIBE — heartbeat interval, etc.]
- TLS setup at the edge: [DESCRIBE]
Build the config:
1. **The upgrade map** — a `map $http_upgrade $connection_upgrade {}` block at the `http` level with `default upgrade;` and `'' close;`. Explain why this exists instead of hardcoding `Connection upgrade` (it must collapse to `close` for normal requests).
2. **The real-time location** — `proxy_http_version 1.1`, `proxy_set_header Upgrade $http_upgrade`, `proxy_set_header Connection $connection_upgrade`, plus the standard forwarding headers.
3. **Timeouts** — `proxy_read_timeout` and `proxy_send_timeout` sized to comfortably exceed the client's heartbeat interval. Explain that the 60s default is the usual cause of "drops after a minute."
4. **Buffering** — for SSE, set `proxy_buffering off;` and explain that buffering delays or batches the event stream; note when it is safe to leave on for plain WebSockets.
5. **Coexistence** — if real-time traffic shares a server block with normal HTTP, show how to isolate the WS settings to the real-time `location` so you don't apply huge timeouts site-wide.
Output: (a) the complete `map` + `location` config, commented, (b) a table of each directive and the symptom you'd see if it were missing, (c) a curl/websocat smoke test that proves a `101 Switching Protocols` response, plus the `nginx -t` line. Validate with `nginx -t` and reload — never edit a live prod config in place.
Why this prompt works
Almost every WebSocket-through-NGINX outage traces to one of three things, and this prompt makes all three explicit requirements. First is the Upgrade map: people hardcode proxy_set_header Connection upgrade, which works until a normal request comes through carrying a stale Connection header, so the idiomatic answer is the map that collapses to close for non-upgrade traffic. Second is the read timeout — NGINX closes an idle proxied connection after 60 seconds by default, which is exactly the “drops after a minute” symptom users report. Third is buffering, which silently breaks SSE by batching the stream.
By asking the model to attach a symptom to each directive, the prompt produces a config you can reason about rather than copy blindly. When a connection misbehaves later, you already have the mental model: no 101? check the map. Drops at exactly 60s? check the timeout. Events arrive in bursts? check buffering.
The smoke-test requirement is the load-bearing part. nginx -t happily validates a config that drops every WebSocket, because a missing Upgrade header is syntactically fine. Proving a real 101 Switching Protocols handshake — with websocat or a curl upgrade request — is the only way to know the proxy actually works before you tell the on-call channel it’s fixed.
Related prompts
-
NGINX Performance Tuning Prompt
Tune worker_processes, keepalive, buffers, sendfile, and connection limits to your actual hardware and traffic — producing a justified config diff, not cargo-culted values copied from a blog.
-
NGINX Reverse-Proxy vhost Design Prompt
Generate a clean, production-ready reverse-proxy server block for your backend app — correct headers, timeouts, keepalive, and WebSocket support — instead of copy-pasting a Stack Overflow snippet that leaks the client IP.