要让 Nginx 真正稳定代理 WebSocket,关键在于透传 Upgrade 和 Connection 头、关闭 proxy_buffering、设 proxy_read_timeout 和 proxy_send_timeout 为 86400、启用 tcp_nodelay on,并避免使用 proxy_cache 和错误的 Connection 头设置。

要让 Nginx 真正稳定代理 WebSocket,关键不是凑齐几行配置,而是理解它为何会静默断连、握手失败——问题往往出在协议升级被截断、缓冲干扰帧流、或超时粗暴中断连接。Nginx 1.3.13+ 原生支持,但默认配置完全不适用 WebSocket 场景。
透传协议升级头,确保握手成功
WebSocket 握手依赖两个逐跳(hop-by-hop)HTTP 头:Upgrade 和 Connection。Nginx 默认丢弃它们,必须显式透传:
- proxy_http_version 1.1; —— HTTP/1.0 不支持 Upgrade,缺了这句,握手必然失败
- proxy_set_header Upgrade $http_upgrade; —— 使用变量而非硬编码 "websocket",兼容 MQTT、STOMP 等其他 upgrade 场景
- proxy_set_header Connection "upgrade"; —— 必须是固定字符串 "upgrade",不是 $http_connection(后者可能是 keep-alive,会掩盖升级意图)
关闭干扰长连接的默认行为
WebSocket 是全双工、无请求-响应模型的长生命周期 TCP 连接,Nginx 默认策略恰恰与之冲突:
- proxy_buffering off; —— 防止后端发送的多个 TEXT/BINARY 帧被缓存合并,造成粘包或延迟
- proxy_read_timeout 86400; —— 设为 24 小时,避免空闲期间 Nginx 单方面关闭连接(默认仅 60 秒)
- proxy_send_timeout 86400; —— 同步调大,保障后端心跳或大数据分片能完整发出
- tcp_nodelay on; —— 绕过 Nagle 算法,小帧(如光标移动、按键事件)立即送达,对协同类应用很关键
避免常见配置陷阱
很多看似“合理”的写法反而导致连接不可靠:
- 不用 add_header Access-Control-Allow-Origin "*" —— WebSocket 跨域由后端在 101 响应中返回 CORS 头,Nginx 只需透传,加了反而可能覆盖后端设置
- 不启用任何 proxy_cache_* 指令 —— WebSocket 消息不可缓存,启用会导致连接直接失败
- 不设 proxy_set_header Connection $http_connection —— 客户端 Connection 值常含多个字段(如 "Upgrade, keep-alive"),Nginx 会清理 Upgrade,只剩 keep-alive,后端收不到升级信号
- 慎用 map 动态构造 Connection —— 虽更严谨,但若配置不当(如未配 default),非 upgrade 请求可能触发 Connection: close,意外中断普通 HTTP 流量
WSS 支持与生产建议
若前端使用 wss://,需额外注意协议一致性:
- proxy_set_header X-Forwarded-Proto $scheme; —— 让后端知道原始是 HTTPS,避免生成 http:// 链接
- SSL 配置推荐启用 http2 on 和 TLSv1.2/TLSv1.3,提升握手和后续帧传输效率
- 上游服务建议配置 keepalive 32;,复用后端连接,降低频繁建连开销
- 日志中可添加 $upstream_http_upgrade 和 $upstream_http_connection 变量,用于排查握手头是否真实到达后端


















