Skip to content

How to Fix Nginx WebSocket Proxy Error

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about How to Fix Nginx Websocket Proxy Error. We cover key concepts, practical examples, and best practices.

Nginx WebSocket proxy fails with <a href="/apis/websocket/">WebSocket</a> connection to 'wss://example.com/ws' failed: Error during <a href="/apis/websocket/">WebSocket</a> handshake: Unexpected response code: 400 — the required upgrade headers are not being forwarded to the upstream server.

The Problem

WebSocket connection to 'wss://example.com/ws' failed:
Error during WebSocket handshake: Unexpected response code: 400

Step-by-Step Fix

Step 1: Configure WebSocket proxy headers

location /ws/ {
    proxy_pass http://websocket-backend: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;
}

Step 2: Add timeout settings

location /ws/ {
    proxy_pass http://websocket-backend:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # WebSocket timeout settings
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
}

Step 3: Handle multiple WebSocket services

map $http_upgrade $connection_upgrade {
    default  upgrade;
    ''       close;
}

server {
    location /ws/ {
        proxy_pass http://ws-backend:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

Step 4: Test WebSocket connection

# Install wscat first
npm install -g wscat

# Test the WebSocket endpoint
wscat -c ws://localhost/ws/

Step 5: Check Nginx error logs

tail -f /var/log/nginx/error.log | grep -i websocket

Prevention Tips

  • Always set proxy_http_version 1.1 for WebSocket proxying
  • Configure proxy_read_timeout for long-lived WebSocket connections
  • Use the map block approach for the Connection header
  • Monitor active WebSocket connections with stub_status

Common Mistakes with websocket proxy

  1. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  2. Non-exhaustive pattern matches that compile with warnings then crash at runtime
  3. Misunderstanding that String is [Char] with poor performance for large text operations

These mistakes appear frequently in real-world NGINX code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does WebSocket handshake fail with 400 through Nginx?

The most common cause is missing the Upgrade and Connection headers. Nginx strips these headers by default for security. Adding proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection "upgrade" resolves the issue.

How long should proxy_read_timeout be for WebSocket connections?

WebSocket connections can remain open for hours. Set proxy_read_timeout to at least 86400s (24 hours) or higher. Some production setups use 604800s (7 days). Match the timeout to your application's keepalive requirements.

Can Nginx proxy multiple WebSocket endpoints?

Yes, use multiple location blocks for different WebSocket paths. Each can proxy to a different upstream. Use the map directive for the Connection header to avoid repeating the upgrade logic in each location block.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro