5月27日 22:12

Nginx 如何配置 WebSocket 代理?

Nginx 如何配置 WebSocket 代理?

WebSocket 建立在 HTTP/1.1 之上,通过 Upgrade 机制将 HTTP 连接升级为全双工长连接。Nginx 默认会清除 Upgrade 头,所以必须手动配置才能正确代理 WebSocket。

核心配置(三行必写)

nginx
location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
  • proxy_http_version 1.1:WebSocket 要求 HTTP/1.1,Nginx 默认用 1.0
  • Upgrade $http_upgrade:转发客户端的协议升级请求
  • Connection "upgrade":告知 Nginx 这不是普通 HTTP,需要保持升级状态

推荐用 map 管理 Connection 头

多 location 场景下,硬编码 "upgrade" 会导致非 WebSocket 请求也被标记。用 map 按需切换更安全:

nginx
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }

没有 Upgrade 头时走 close,普通请求不受影响。

超时:为什么连着连着就断了?

Nginx 的 proxy_read_timeout 默认 60 秒。WebSocket 是长连接,如果 60 秒内没有数据传输,Nginx 会主动断开。解决办法:

nginx
proxy_read_timeout 3600s; # 1小时 proxy_send_timeout 3600s; proxy_connect_timeout 60s; # 建连超时保持短即可

按业务调,不是越大越好。过长超时意味着僵死连接不会被回收。

WSS(WebSocket over TLS)

在 SSL server 块里照加那三行即可,Nginx 负责 TLS 卸载,后端仍用 ws://

nginx
server { listen 443 ssl; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }

负载均衡要注意会话保持

WebSocket 是有状态长连接,轮询策略会导致重连时切到不同后端。必须用 ip_hash

nginx
upstream ws_backend { ip_hash; server 10.0.0.1:8080; server 10.0.0.2:8080; }

如果后端是无状态的(如用 Redis Pub/Sub 做消息同步),也可以用轮询。

追问:连接断开怎么排查?

  1. 查 Nginx error log,确认是否超时断开
  2. 检查 Upgrade / Connection 头是否正确转发
  3. 确认 proxy_buffering off 已设置,避免数据被缓冲
  4. 检查防火墙或 CDN 是否拦截长连接
  5. curl -H "Upgrade: websocket" 手动测试握手是否返回 101
标签:Nginx