Nginx代理WebSocket需透传Origin、设proxy_read_timeout≥86400、并强制配置proxy_http_version 1.1、Upgrade和Connection头,否则握手失败或60秒断连。

WebSocket 连接在 Nginx 反向代理下既需要防止跨站劫持,又要避免无故断连。关键不在后端“能不能连”,而在于 Nginx 是否把原始请求信息完整、准确地交过去,以及是否为长连接留出足够空间。
Origin 校验为什么必须由后端做,Nginx 不该“代劳”
Nginx 本身不校验 Origin,也不应清除或伪造它——它的角色是透传,不是决策者。浏览器自动添加的 Origin 头(如 https://admin.example.com)是唯一可信来源标识,后端需据此白名单比对。常见错误包括:
- 在 Nginx 中写
proxy_set_header Origin "",导致后端收不到原始值,校验失效 - 误用
Sec-WebSocket-Origin(已废弃),忽略现代浏览器只发标准Origin - 用
if ($http_origin !~ ^https?://(admin\.example\.com|app\.example\.com)$) { return 403; },既低效又易绕过,且无法处理协议/端口差异
正确做法是:Nginx 完全保留 $http_origin,让后端(如 Node.js 的 ws 库或 Go 的 Gorilla WebSocket)执行带协议、主机名、端口(可选)的精确匹配,并支持开发环境豁免(如 localhost:3000)。
60 秒断连的真正原因和解法
不是网络不稳定,而是 Nginx 默认的 proxy_read_timeout 60; 在起作用。它表示“从后端读数据的空闲等待上限”,WebSocket 空闲时没数据流,Nginx 就主动关连接。这不是 bug,是设计如此——它本就为 HTTP 短连接优化。
-
proxy_read_timeout 86400;(24 小时)是最常用且稳妥的值,应 ≥ 后端心跳间隔(如 Swoole 的heartbeat_idle_time) -
proxy_send_timeout 86400;防止大消息或弱网下发被中断 -
proxy_connect_timeout 10;控制建连阶段超时,避免堆积失败连接
注意:这些值设得再大,也不会占用额外资源;Nginx 对空闲 WebSocket 连接几乎零开销,只守着一个 TCP socket。
握手失败的三大配置硬性要求
Origin 校验再严,连接都建立不了也白搭。99% 的 Handshake failed due to invalid Upgrade header 错误,都源于以下三项未显式配置:
-
proxy_http_version 1.1;—— HTTP/1.0 不支持 Upgrade,必须强制启用 1.1 -
proxy_set_header Upgrade $http_upgrade;—— 原样转发客户端的Upgrade: websocket -
proxy_set_header Connection "upgrade";—— 不能写$http_connection,因为浏览器可能发keep-alive,必须固定设为upgrade
进阶建议:用 map 指令做更健壮的 Connection 处理,例如在 http 块中定义:map $http_upgrade $connection_upgrade { default upgrade; '' close; },再在 location 中写 proxy_set_header Connection $connection_upgrade;。
HTTPS(WSS)下不可忽略的细节
wss:// 连接失败,往往不是证书问题,而是代理链路断裂:
- Nginx SSL 配置必须完整:含
ssl_certificate、ssl_certificate_key、明确的ssl_protocols TLSv1.2 TLSv1.3 - 不要开启
http_v2 on;并同时代理 WebSocket——HTTP/2 不支持 Upgrade 机制,会静默降级或失败 - 确保前端访问的是
wss://your-domain.com/ws/,而 Nginx 的location /ws/ { ... }是直接匹配,不经过rewrite或内部跳转,否则 Origin 和路径可能被污染
验证方式很简单:用浏览器 DevTools Network 标签看 WebSocket 请求响应状态码是否为 101 Switching Protocols,响应头是否含 Upgrade: websocket 和 Connection: upgrade。


















