WebSockets, timeouts and buffering

NGINX · Advanced · 12 min

Real-time features and streaming responses break behind a default proxy configuration.

WebSockets start as an HTTP request with Upgrade: websocket and Connection: Upgrade. These are hop-by-hop headers, so NGINX doesn't forward them unless told to. You need HTTP/1.1 to the backend and the two headers set explicitly. A map makes Connection correct for both WebSocket and normal requests.

Timeouts: proxy_read_timeout (default 60s) is the maximum time between two reads from the backend. An idle WebSocket or a long-polling request is closed after it, so raise it for those locations, or have the application send pings. proxy_send_timeout is the write equivalent; proxy_connect_timeout limits connection setup.

Buffering: by default NGINX reads the backend's response into memory buffers (and temporary files if large), then sends it to the client. That frees the backend quickly even for slow clients, which is usually what you want. But it delays streaming responses such as Server-Sent Events, LLM token streams or progress output. Options:

  • proxy_buffering off; in that location.
  • The backend can send X-Accel-Buffering: no for individual responses.

Request bodies are also buffered fully by default; proxy_request_buffering off; streams uploads directly to the backend.

Example

map $http_upgrade $connection_upgrade {      # http context
    default upgrade;
    ''      close;
}

server {
    listen 80;
    location /ws/ {
        proxy_pass http://127.0.0.1:9000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 1h;                 # idle sockets stay open
    }
    location /events {                         # Server-Sent Events
        proxy_pass http://127.0.0.1:8000;
        proxy_buffering off;                   # flush each event immediately
        proxy_read_timeout 10m;
    }
}

Remember

  • WebSockets need proxy_http_version 1.1 plus Upgrade and Connection headers
  • proxy_read_timeout closes idle upstream connections (60s default)
  • Turn proxy_buffering off for streaming responses

Watch out for

  • WebSocket connections dropping every 60 seconds because proxy_read_timeout was left at the default.

Check yourself

  1. A streaming endpoint delivers all its output at once at the end, only when behind NGINX. Likely fix?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: nginx.org/en/docs/http/websocket.html

Builds on

Unlocks

Nothing builds on this yet.