要让Nginx稳定代理WebSocket并维持长连接,核心是透传Upgrade和Connection头、关闭proxy_buffering与proxy_cache、设proxy_read_timeout和proxy_send_timeout为86400、启用tcp_nodelay,并确保路径精确匹配及会话绑定。

要让 Nginx 稳定代理 WebSocket 并维持长连接,核心不是堆参数,而是让每个配置项都贴合 WebSocket 的通信本质:它是基于 HTTP 升级的、全双工、无请求-响应模型、生命周期长、对延迟和顺序敏感的 TCP 连接。默认配置天然与之冲突,必须针对性调整。
透传升级头,确保握手一次成功
WebSocket 握手失败(返回 200/400 而非 101)几乎全是这里出问题。Nginx 默认丢弃 Upgrade 和 Connection 这两个逐跳头,后端根本收不到升级信号。
- proxy_http_version 1.1 必须写死——HTTP/1.0 不支持 Upgrade,缺了这句,Nginx 会静默降级转发
- proxy_set_header Upgrade $http_upgrade 用变量而非硬编码 "websocket",兼容 MQTT、STOMP 等非标准客户端
- proxy_set_header Connection "upgrade" 注意是带英文双引号的字面量 upgrade,不能写成 $http_connection(它常为 keep-alive,会掩盖升级意图)
关闭缓冲与干扰机制,避免帧流被截断
WebSocket 数据是连续帧流(TEXT/BINARY/PING/PONG),Nginx 默认行为会缓存、合并、延迟发送,造成粘包、卡顿或乱序。
- proxy_buffering off 关在具体的 location 块里(如 /ws/),不能放全局;否则响应帧会被攒批发出
- proxy_cache off 显式禁用缓存——WebSocket 消息不可缓存,启用会导致连接直接失败
- tcp_nodelay on 绕过 Nagle 算法,小帧(如光标移动、VAD 触发)立即送达,对协同类、音视频类应用很关键
超时设置要远大于心跳间隔,且上下对齐
连接“突然断开”“反复重连”,90% 是 proxy_read_timeout 太小。WebSocket 空闲时不发数据,只靠心跳维持活跃,Nginx 默认 60 秒就会单方面关连接。
- proxy_read_timeout 86400(24 小时)最稳妥;若后端心跳 30 秒,至少设为 90 秒以上
- proxy_send_timeout 86400 同步调大,防止后端推送广播消息、大音频包或慢响应时被中断
- 所有超时值必须与后端框架(Netty/Swoole/Spring Boot)的读写超时、心跳检测周期严格对齐,否则出现“一端已关、另一端还在等”
路径精确匹配 + 会话绑定,防止轮询漂移
分布式部署下,WebSocket 连接状态通常存在内存中,若请求被轮询打到不同后端,会话丢失、消息丢失、报错 1006。
- 用明确路径匹配,例如 location /ws/ { ... },避免用 location / {} 兜底,防止静态资源或 API 冲突
- 启用会话保持:ip_hash(简单有效,适合公网 IP 分散场景)或 sticky cookie(需 Nginx Plus 或第三方模块,支持故障转移)
- upstream 中加 keepalive 32,复用到后端的空闲连接,减少握手开销


















