Reverse Proxy & APIswebsocket.conf

How to Proxy WebSockets in Nginx (Socket.io, WS, WSS)

WebSockets begin as an HTTP handshake that requests a protocol upgrade to ws:// or wss://. Nginx terminates HTTP by default and closes idle connections unless explicit Upgrade and Connection headers are configured.

Interactive Nginx Config Generator

websocket.conf
/etc/nginx/sites-available/websocket.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.com;

    location /socket.io/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # WebSocket handshake upgrade headers
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Keep idle WebSockets alive for 1 day instead of default 60s
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Directives & Architecture Explained

proxy_http_version 1.1;

Required for WebSocket handshakes. The default Nginx proxy protocol is HTTP 1.0 which does not support persistent multiplexing.

proxy_set_header Upgrade $http_upgrade;

Passes the client upgrade token ("websocket") to the upstream application.

proxy_set_header Connection $connection_upgrade;

Translates connection header dynamically using map to ensure clean close when no upgrade is requested.

proxy_read_timeout 86400s;

Prevents Nginx from killing inactive WebSocket connections after the default 60-second idle timeout.

Production Verification & Reload Workflow

sudo nginx -t

Check configuration and map block syntax

wscat -c ws://ws.example.com/socket.io/?EIO=4&transport=websocket

Connect using wscat CLI to verify instant protocol upgrade and echo responses

Production Troubleshooting Tips

  • β€’The map $http_upgrade directive MUST be placed inside the http {} block, outside server {}.
  • β€’If connections disconnect exactly after 60 seconds, verify that proxy_read_timeout has been increased.
  • β€’For SSL WebSockets (wss://), ensure the server block listens on 443 ssl and has valid TLS certificates.

Frequently Asked Questions

Why does Nginx disconnect WebSockets after 60 seconds?

The default proxy_read_timeout is 60 seconds. If neither the client nor server sends a ping/pong frame within that window, Nginx terminates the TCP socket.

What does the map block achieve?

It sets $connection_upgrade to "upgrade" when the Upgrade header is present, and "close" when it is empty, preserving HTTP connection standards.