Configure Tengine WebSocket reverse proxy

2026-09-29

AdSense Slot

Your chat or real-time feature works locally, but behind Tengine the WebSocket handshake fails with 400 Bad Request or disconnects every few seconds. The reason: WebSocket needs the HTTP Upgrade headers forwarded explicitly — a plain proxy_pass does not do that. Here is the config that fixes it, and the timeout that stopped my connections from dropping.

The minimum working config

location /ws/ {
    proxy_pass http://backend_pool;
    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_read_timeout 3600s;
}

The two lines that matter for WebSocket:

Why connections drop after a minute

The default proxy_read_timeout is 60 seconds. A WebSocket that idles longer than that gets cut by Tengine even though the connection is healthy. Raising it to an hour keeps long-lived sockets alive:

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

Common mistakes I have debugged

Verify the handshake

curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  https://yourdomain.com/ws/

A successful response starts with 101 Switching Protocols.

Summary

Forward Upgrade and Connection: upgrade, raise proxy_read_timeout, and scope it to the socket path. If handshakes still fail, the backend side is the next suspect. And if your upstream is load-balanced, my load balancer guide shows how to keep sticky sockets working.

AdSense Slot