Facebook Pixel

Adding WebSocket Support to Nginx Socket.io Proxy Configuration

Learn how to update your Nginx config to support WebSocket connections for Socket.io the Upgrade and Connection headers, and common issues.

Adding WebSocket Support to Nginx

WebSocket connections require special Nginx configuration. Without it, Socket.io won't work behind Nginx.

The Problem

WebSockets start as an HTTP request and upgrade to a WebSocket connection. Nginx needs to forward this upgrade request to the backend.

The Solution: Upgrade and Connection Headers

server { listen 443 ssl; server_name api.yourdomain.com; # API and WebSocket location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header 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; proxy_set_header X-Forwarded-Proto $scheme; } }

Dedicated Socket.io Location (Recommended)

For better organization, separate Socket.io from API routes:

server { listen 443 ssl; server_name api.yourdomain.com; # REST API location /api/ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # Socket.io WebSocket location /socket.io/ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header 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; } }

Key Headers Explained

proxy_http_version 1.1 WebSocket requires HTTP/1.1. Default is HTTP/1.0 which doesn't support upgrades.

Upgrade $http_upgrade Passes the client's Upgrade header to the backend. This tells the backend "the client wants to upgrade the connection to WebSocket."

Connection "upgrade" Tells Nginx to upgrade the connection. Without this, Nginx closes the connection after the HTTP response.

WebSocket Timeouts

WebSocket connections are long-lived. Increase the timeout:

location /socket.io/ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Increase timeouts for long-lived connections proxy_read_timeout 86400s; # 24 hours proxy_send_timeout 86400s; # 24 hours }

Without long timeouts, Nginx closes WebSocket connections after 60 seconds (default).

Load Balancing with WebSocket

For multiple Node.js instances with WebSocket:

upstream nodejs_backend { ip_hash; # Sticky sessions same client goes to same instance server 127.0.0.1:3000; server 127.0.0.1:3001; server 127.0.0.1:3002; } server { location /socket.io/ { proxy_pass http://nodejs_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }

ip_hash is critical it ensures the same client always connects to the same Node.js instance. Without it, the initial HTTP upgrade and subsequent WebSocket frames might go to different instances.

Testing WebSocket Support

# Test the Nginx config sudo nginx -t # Reload sudo systemctl reload nginx # Test from the frontend # Open browser console and check for successful Socket.io connection: # "Connected to server" # Check Nginx error log if issues sudo tail -f /var/log/nginx/error.log

Common WebSocket Issues

Socket.io connection fails:

  • Missing Upgrade/Connection headers
  • HTTP/1.0 instead of 1.1
  • Short proxy_read_timeout (connection closes after 60s)

WebSocket works locally but not in production:

  • Nginx not configured for WebSocket
  • Cloudflare proxy not configured (enable WebSockets in dashboard)
  • Firewall blocking WebSocket upgrade

Duplicate connections:

  • Not using ip_hash with load balancing
  • Client connecting to different instances on reconnection

The Takeaway

Adding WebSocket support to Nginx requires: proxy_http_version 1.1, Upgrade $http_upgrade, and Connection "upgrade" headers. Without these, Socket.io won't work. Use a dedicated /socket.io/ location block for clarity. Set long proxy_read_timeout (86400s) for persistent connections. Use ip_hash with load balancing for sticky sessions. Test with nginx -t and reload.

Add proxy_http_version 1.1, proxy_set_header Upgrade $http_upgrade, and proxy_set_header Connection 'upgrade' to the location block. These headers tell Nginx to upgrade the HTTP connection to WebSocket and forward it to the backend. Without them, Socket.io won't work.

Missing the Upgrade and Connection headers. WebSockets start as HTTP and upgrade to WebSocket. Without proxy_set_header Upgrade and Connection 'upgrade', Nginx doesn't forward the upgrade request, and the WebSocket connection fails. Also, HTTP/1.0 (default) doesn't support upgrades use proxy_http_version 1.1.

Set proxy_read_timeout and proxy_send_timeout to 86400s (24 hours). WebSocket connections are long-lived. The default 60-second timeout causes Nginx to close the connection, breaking the WebSocket. Long timeouts keep connections alive.

Use ip_hash in the upstream block for sticky sessions. This ensures the same client always connects to the same Node.js instance. Without ip_hash, the HTTP upgrade and WebSocket frames might go to different instances, causing connection failures.

Check Nginx error logs (sudo tail -f /var/log/nginx/error.log). Verify the Upgrade and Connection headers are present. Test with nginx -t. Check the browser console for Socket.io connection errors. If using Cloudflare, enable WebSockets in the dashboard. Verify proxy_read_timeout is long enough.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.