要让 nginx 稳定代理 websocket 并保持长连接不中断,关键是透传 upgrade 和 connection 头、设 proxy_read_timeout 等超时值略大于后端心跳间隔(如 90 秒)、关闭 proxy_buffering 与 proxy_cache、启用 tcp_nodelay,并通过精确 location 匹配和会话保持确保请求路由一致。

要让 Nginx 稳定代理 WebSocket 并保持长连接不中断,关键不是简单调大超时值,而是让每一项配置都贴合 WebSocket 的通信本质:它是一次 HTTP 升级后建立的全双工、无请求-响应模型、依赖心跳维持的 TCP 长连接。Nginx 默认按短连接处理,必须显式绕过默认行为。
透传协议升级头,确保握手成功
WebSocket 握手失败(返回 200/400 而非 101)绝大多数源于 Upgrade 和 Connection 头被过滤或改写:
- proxy_http_version 1.1; —— 必须强制使用 HTTP/1.1,HTTP/1.0 不支持 Upgrade,缺了这句会静默降级
- proxy_set_header Upgrade $http_upgrade; —— 使用变量转发客户端原始值(如 websocket、mqtt),不能硬写 "websocket"
- proxy_set_header Connection "upgrade"; —— 必须是带英文双引号的字面量 upgrade,不能用 $http_connection(它常含 keep-alive,会覆盖升级意图)
超时设置要匹配心跳节奏,而非盲目拉长
Nginx 默认 proxy_read_timeout=60s 是“准时断连”的元凶。WebSocket 空闲时不发业务数据,只靠后端定时 ping/pong 维持活跃,超时值必须大于最大心跳间隔:
- proxy_read_timeout 90; —— 若后端每 30 秒发一次 pong,此处至少设为 60,建议留出余量设为 90 或更高
- proxy_send_timeout 90; —— 同步调大,避免向后端推送广播消息、大帧或慢响应时被中途切断
- keepalive_timeout 90; —— 保持客户端到 Nginx 的连接存活,与上游超时对齐更稳妥
关闭缓冲与缓存,保障帧流实时透传
WebSocket 数据以 TEXT/BINARY/PING/PONG 帧形式连续双向流动,Nginx 默认机制会缓存、合并、延迟甚至丢帧:
- proxy_buffering off; —— 必须放在具体的 location /ws/ { ... } 块中,不可放全局
- proxy_cache off; —— 显式禁用,防止 Upgrade 请求被缓存命中返回 200
- tcp_nodelay on; —— 绕过 Nagle 算法,小帧(如光标移动、按键、VAD 触发)立即发出,降低端到端延迟
路径匹配与会话绑定,防止连接漂移
分布式部署下,若后续帧被轮询打到不同后端,因连接状态通常存在内存中,必然导致 1006 错误或消息丢失:
- 用 location /ws/ { ... } 或 location = /ws { ... } 精确/前缀匹配,避免被 rewrite 或兜底 location 拦截
- 集群场景启用会话保持:ip_hash(简单有效)、sticky cookie(兼容 CDN 和动态 IP)、或后端共享状态(如 Redis 存储连接映射)
- upstream 中可加 keepalive 32; 复用到后端的空闲连接,减少握手开销











