linux下nginx代理websocket生产级稳定的关键是四点:透传upgrade/connection头、分层设置proxy_read_timeout和proxy_send_timeout(建议86400s)、负载均衡启用ip_hash等会话粘滞策略、禁用proxy_buffering与proxy_cache并配置动态dns解析。

Linux 下 Nginx 代理 WebSocket 要真正稳在生产环境,关键不在“能不能连上”,而在于“连上后能不能一直不掉、不卡、不乱分”。很多配置看似跑通了,一上量、一过夜、一换网络环境就出问题,根源往往是协议理解偏差 + 参数组合失当。下面从四个最常踩坑的维度讲清楚怎么做。
协议升级必须显式透传,三行 header 缺一不可
WebSocket 握手本质是 HTTP 请求里夹带“升级指令”,Nginx 默认会过滤 Upgrade 和 Connection 这两个逐跳头(hop-by-hop headers),导致后端根本收不到升级意图,返回 200 或 502 而非 101 Switching Protocols。
- proxy_http_version 1.1:必须显式声明,HTTP/1.0 不支持 Upgrade 机制
- proxy_set_header Upgrade $http_upgrade:用变量取客户端原始值,兼容不同客户端(如某些设备发的是 h2c)
- proxy_set_header Connection "upgrade":必须硬写字符串 "upgrade",不能用 $http_connection(它常为 keep-alive)
这三行必须放在 location 块内,server 或 http 级别配置无效。漏掉任意一行,握手必失败。
超时参数要分层设,不能只调 proxy_read_timeout
WebSocket 是空闲长连接,Nginx 默认 proxy_read_timeout 60 意味着只要后端 60 秒没发数据,Nginx 就主动断 TCP —— 用户看到的就是“突然掉线”,日志里却无报错。
-
proxy_read_timeout:建议设为
86400(24 小时)或 ≥ 客户端心跳间隔 × 3;避免设为 0,部分版本行为未定义 - proxy_send_timeout:同步设为同等值,防止后端推送延迟(如批量行情广播)触发中断
-
proxy_connect_timeout:保持默认
30s即可,它只影响建连阶段,不影响已建立的长连接
注意:keepalive_timeout 对 WebSocket 无效,改它没用;send_timeout(非 proxy_send_timeout)也不起作用。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
负载均衡必须保证会话粘滞,轮询直接导致业务异常
WebSocket 连接是有状态的。用户 A 和后端节点 1 建立连接后,其 session、消息队列、在线状态都存在该节点内存中。若下一次 ping 或消息被轮询到节点 2,后者无上下文,只能断连或返回错误。
- ip_hash:最简单可靠,Nginx 原生支持,按客户端 IP 哈希固定后端;适合出口 IP 较分散的场景
- least_conn:适合连接生命周期差异大、且后端有统一 session 存储(如 Redis)的架构
- 避免纯 round-robin:上线即掉线,尤其在 IM、协作类业务中表现明显
如果使用容器或云环境,IP 可能复用(如 NAT 网关后大量用户共用一个出口 IP),此时需配合应用层路由(如按 user_id 或 token 哈希)或 sticky cookie(需编译第三方模块)。
实时性与稳定性兼顾,禁用缓冲 + 动态 DNS 解析
WebSocket 数据讲究“推即达”,Nginx 默认开启的响应缓冲和 Nagle 算法会攒包,引入毫秒级延迟,对协同编辑、实时游戏等场景敏感。
- proxy_buffering off:禁用响应缓冲,确保每帧数据立即转发
- proxy_cache off:避免缓存 WebSocket 响应(它本就不该被缓存)
- resolver + valid=30s:在 Docker/K8s 等动态环境中,必须配置 DNS 解析器并设置缓存有效期,否则后端 Pod IP 变更后 Nginx 仍连旧地址
例如:resolver 127.0.0.11 valid=30s;(Docker 内置 DNS)或 resolver 8.8.8.8 valid=10s;(公网环境)。










