nginx代理websocket必须显式透传upgrade和connection头,否则握手失败:需在location块中配置proxy_http_version 1.1、proxy_set_header upgrade $http_upgrade、proxy_set_header connection "upgrade",并设proxy_read_timeout和proxy_send_timeout为86400、proxy_buffering off。

WebSocket 代理中,Nginx 必须主动透传 Upgrade 和 Connection 这两个关键请求头,否则握手直接失败——浏览器发了 Upgrade: websocket,后端却收不到,只能返回 200 OK,连接永远卡在“正在建立”状态。
必须显式设置的三行头转发规则
这三项缺一不可,且必须写在 location 块内、紧邻 proxy_pass 指令下方:
- proxy_http_version 1.1; —— HTTP/1.0 不支持协议升级机制,这是所有配置的前提
-
proxy_set_header Upgrade $http_upgrade; —— 用内置变量动态捕获客户端原始值(可能是
websocket、mqtt或自定义协议),不能写死为"websocket" -
proxy_set_header Connection "upgrade"; —— 注意是带双引号的固定字符串
"upgrade";若误用$connection_upgrade又未提前定义 map 块,该变量为空时会变成Connection: close,导致握手被拒绝
为什么不能依赖默认行为
Upgrade 和 Connection 属于“逐跳头”(hop-by-hop headers),Nginx 默认会丢弃它们,不加声明就等同于把握手申请中途拦截。这不是功能缺失,而是设计使然:Nginx 本身不处理 WebSocket 帧,只负责把升级意图原样、干净地交给后端服务。
多级代理时的头传递要点
如果流量经过多个 Nginx 层(如 CDN → 边缘 Nginx → 应用 Nginx),每一层都必须独立配置上述三行。任意一层漏掉,握手就在那一层中断,后端日志里甚至看不到请求痕迹。常见表现是 400 Bad Request 或无响应,但 access log 可能显示 200,极具迷惑性。
配套设置增强稳定性
仅转发头还不够,还需防止 Nginx 主动断连:
- proxy_read_timeout 86400; —— 避免空闲超时(默认仅 60 秒),建议设为 24 小时
- proxy_send_timeout 86400; —— 匹配发送侧,尤其应对服务端批量推送或大消息分片
- proxy_buffering off; —— WebSocket 是帧流,缓冲会导致延迟、粘包或握手失败
- 禁用所有 proxy_cache_* 指令 —— WebSocket 消息不可缓存,启用即出错











