WebSocket 在 Nginx 后断连主因是默认按 HTTP 短连接处理:60 秒空闲关闭、丢弃 Upgrade 头、后端收不到握手请求;须同时配置 proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade",并设 proxy_read_timeout ≥ 心跳间隔×2,upstream 启用 keepalive 与 ip_hash 粘性调度,HTTPS 下需完整证书链、显式 TLS 版本且禁用 HTTP/2。

WebSocket 在 Nginx 后面断连,不是“没开负载均衡”,而是默认当 HTTP 短连接处理——60 秒空闲就关,Upgrade 头被丢,后端根本收不到握手请求。必须显式覆盖这三类行为:协议版本、关键头部、超时逻辑。
proxy_http_version 1.1 和 Upgrade/Connection 头必须同时存在
只设 proxy_http_version 1.1 不够,只传 Upgrade 头也不行。Nginx 要同时满足两个条件才能触发 WebSocket 升级流程:
-
proxy_http_version 1.1:HTTP/1.0 不支持Upgrade,没有这句,后端永远收不到升级意图 -
proxy_set_header Upgrade $http_upgrade:客户端发的是Upgrade: websocket,Nginx 默认不透传,必须手动挂载 -
proxy_set_header Connection "upgrade":注意是硬编码的"upgrade"字符串,不是$http_connection;Nginx 默认设Connection: close,这句才是告诉它“别关,要升”
漏掉任意一个,浏览器 Network 面板里看到的响应状态码就是 200 而非 101,或者直接报 Handshake failed due to invalid Upgrade header: null。
proxy_read_timeout 必须远大于业务空闲时间
Nginx 的 proxy_read_timeout 控制它等待后端响应的最长时间。WebSocket 没有“响应”概念,只有持续帧流;一旦后端几秒没发数据(比如用户静默),Nginx 就会主动断开连接——默认值 60 秒,正好对应“准时 60 秒断开”现象。
- 设为
proxy_read_timeout 86400(24 小时)是常见起点,但不是万能解;应 ≥ 前端心跳间隔 × 2 - 配套建议加
proxy_send_timeout 86400:防止大消息分片发送时被中途掐断 - 不要只调
keepalive_timeout:那是客户端到 Nginx 的连接保持,不影响 Nginx 到后端的代理超时
如果用 curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" http://host/ws 测试,响应头里有 Upgrade: websocket 但连接几秒后断,基本就是这个超时在作怪。
upstream keepalive 和会话保持缺一不可
负载均衡场景下,光让单个连接不断还不够,得确保同一客户端的后续帧始终打到同一台后端——否则后端没该连接上下文,直接拒收。
- 在
upstream块里加keepalive 32:维持 Nginx 到后端的空闲长连接池,避免每次新帧都建 TCP 连接 - 必须选粘性算法:
ip_hash最简单可靠;least_conn适合连接数波动大的场景,但需配合后端状态同步(如 Redis 存连接映射) - 禁用
proxy_redirect或任何rewrite:WebSocket 路径匹配必须直出,中间改写会污染$http_upgrade变量值
错误日志里反复出现 upstream prematurely closed connection while reading upstream,大概率是请求被轮询到无状态的另一台后端,而非超时本身。
HTTPS 下 wss 连接失败的隐蔽点
wss:// 不只是加个 s,Nginx SSL 配置不全会导致浏览器直接拒绝发起握手,连日志都不留。
- 证书链必须完整:用
openssl s_client -connect host:443 -servername host检查是否返回 VERIFY OK -
ssl_protocols TLSv1.2 TLSv1.3必须显式声明;部分旧系统默认禁用 TLSv1.3,wss 握手会卡住 - 不能启用
http_v2 on同时代理 WebSocket:HTTP/2不支持Upgrade机制,哪怕只在 server 块里开也会干扰proxy_http_version 1.1行为
浏览器控制台若显示 net::ERR_SSL_PROTOCOL_ERROR 或直接无请求发出,先查 SSL 链路,别一头扎进 proxy 配置里。











