nginx代理websocket掉线主因是默认proxy_read_timeout=60s且未透传upgrade/connection头,须在location块中同步配置proxy_http_version 1.1、proxy_set_header upgrade $http_upgrade与connection "upgrade"、proxy_read_timeout和proxy_send_timeout均设为86400、proxy_buffering off及gzip off,并验证101状态码与错误日志无upstream prematurely closed connection。

Linux 下 Nginx 代理 WebSocket 掉线,绝大多数情况不是网络或代码问题,而是 Nginx 默认把长连接当短请求处理——60 秒无数据就主动断开,且关键协议头没透传。真正起效的调整必须同时满足协议升级、超时延长、缓冲禁用三方面,缺一不可。
必须写在 location 块里的协议升级配置
WebSocket 握手依赖 HTTP/1.1 的 Upgrade 机制,Nginx 默认不转发关键头部,后端收不到信号就无法返回 101 状态码:
- proxy_http_version 1.1; —— 否则 HTTP/1.0 不支持协议升级语义
- proxy_set_header Upgrade $http_upgrade; —— 用变量透传原始值(如 websocket、mqtt),不能硬写 "websocket"
- proxy_set_header Connection "upgrade"; —— 注意是双引号包裹的字面量 "upgrade",不是 $http_connection
这三行必须放在匹配 WebSocket 路径的 location /ws/ { } 或 location /signalr/ { } 块内,写在 server 或 http 块顶层无效。
读写超时要同步调大且留余量
proxy_read_timeout 控制 Nginx 等待后端发数据的空闲时间;proxy_send_timeout 控制 Nginx 向客户端发送数据的连续等待时间。两者都默认 60 秒,是“准时 60 秒断连”的根源:
- 设为 proxy_read_timeout 86400;(24 小时)或至少 ≥ 前端心跳间隔 × 3(例如心跳 30 秒,则设 ≥ 90)
- 同步设置 proxy_send_timeout 86400;,防止后端发大消息或 pong 帧时被中途中断
- 不要设为 0:部分 Nginx 版本行为未定义,可能回退到默认值甚至崩溃
关闭缓冲和压缩避免帧结构破坏
WebSocket 是流式双向通信,Nginx 默认启用的缓冲、压缩、缓存会合并、延迟或篡改帧,导致静默断连:
- proxy_buffering off; —— 必须放在同一 location 块中,禁用响应缓冲
-
gzip off; 或确保
gzip_types不包含application/json、text/plain等常用类型 - proxy_cache off; —— WebSocket 消息不可缓存,启用即引发连接失败
验证是否真正生效的关键动作
重启 Nginx 后,不能只看前端“连上了”,要确认底层握手与链路行为正确:
- 浏览器 Network 面板中,WebSocket 请求响应状态码必须是 101 Switching Protocols,且响应头含
Upgrade: websocket和Connection: upgrade - 用 curl 模拟握手:
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" https://your-domain/ws/,检查返回头 - 查看 Nginx 错误日志:
grep "upstream prematurely closed connection" /var/log/nginx/error.log,有则说明仍有头透传或超时问题











