Nginx 代理 WebSocket 要配 header
Nginx 代理 WebSocket 必配的 Header 详解
WebSocket 协议从 HTTP 握手升级而来,Nginx 作为反向代理时需要显式传递升级相关的头部,否则连接会降级为普通 HTTP 或直接失败。本篇将系统梳理 Nginx 代理 WebSocket 时必须配置的 header,并给出可直接用于生产环境的配置片段。
1. WebSocket 升级握手的关键 Header
客户端发起 WebSocket 连接时,会发送以下关键请求头:
Connection: Upgrade– 告知服务器本次连接需要升级协议Upgrade: websocket– 指定升级后的协议为 WebSocketSec-WebSocket-Key– 用于握手的安全密钥Sec-WebSocket-Version– 协议版本
当 Nginx 作为反向代理时,默认不会逐跳传递 Connection 和 Upgrade 头。因为它们是逐跳头(hop-by-hop),HTTP/1.1规范中不能由代理自动转发,必须显式配置。
2. Nginx 中显式设置升级头
在 location 块中添加以下三条指令:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
$http_upgrade是 Nginx 内置变量,原样获取客户端请求中的Upgrade头(取值通常为websocket)。Connection头必须显式设置为"upgrade"(全部小写),表示同意升级。
完整的 WebSocket 代理配置结构:
location /wsapp/ {
proxy_pass http://backend_ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
为什么还要指定 proxy_http_version 1.1?
- HTTP/1.1 默认支持持久连接和协议升级。如果后端期望 HTTP/1.1 语义,而 Nginx 默认以 HTTP/1.0 连接后端,可能导致升级失败。强制设为 1.1 是安全的。
3. 透传真实客户端信息的 Header
WebSocket 后端通常需要客户端的真实 IP 和协议信息,用于日志、鉴权、安全策略。必须添加:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
X-Real-IP:传递客户端的真实 IP(对单一代理链有效)X-Forwarded-For:构建完整的 IP 链,使用$proxy_add_x_forwarded_for会将客户端 IP 追加到已有列表X-Forwarded-Proto:告知后端原始请求的协议(http 或 https),便于后端重定向时构建正确 URL
4. 调整 WebSocket 超时时间
WebSocket 连接可能是长连接的,Nginx 默认的 proxy_read_timeout 为 60 秒,如果应用长时间没有数据帧,连接会被切断。需要根据应用场景调大:
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
也可以按小时写为 1h,但对于多数应用 12 小时或 24 小时更保险。部分场景下可以设置为 1d 避免意外断开。
5. 完整的 WebSocket 代理配置模板
server {
listen 80;
server_name example.com;
location /ws/ {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
# WebSocket 握手必须的头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 透传客户端信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 长连接超时调整
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# 禁用缓冲以支持实时推送(可选但推荐)
proxy_buffering off;
}
}
6. 常见错误与排查
6.1 返回 400 Bad Request 或 426 Upgrade Required
- 检查
proxy_set_header Connection的值是否为全部小写的"upgrade"。部分旧版教程使用"Upgrade"会导致后端无法识别。 - 确认
proxy_http_version 1.1;已配置。
6.2 连接立即断开
查看 proxy_read_timeout 是否过短。WebSocket 协议本身有心跳帧(ping/pong),如果应用层心跳间隔大于 Nginx 超时,会触发断开。
6.3 后端拿到的 IP 全是代理 IP
缺失 X-Real-IP 和 X-Forwarded-For 头,或后端没有从这些头中解析真实 IP(需检查后端框架配置)。
6.4 通过 HTTPS 代理时 WebSocket 失败
若客户端使用 wss://,Nginx 本身需配置 SSL 终端,并正确传递 X-Forwarded-Proto: https。同时确保后端 WebSocket 服务器能够识别该头并信任代理。
6.5 多层代理时 Header 覆盖问题
如果 Nginx 前面还有 CDN 或负载均衡器,需在 Nginx 上使用 $http_x_forwarded_for 和 $http_x_real_ip 来接收上游传来的头,再结合 $remote_addr 添加自身到链中。通用安全写法:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
变量 $proxy_add_x_forwarded_for 会自动包含客户端 IP 以及请求中原有的 X-Forwarded-For,保证链的完整性。
7. 进阶:根据请求头动态决定是否升级
有些应用在同一路径下既有普通 HTTP 请求又有 WebSocket。此时可基于 $http_upgrade 变量做条件判断:
location / {
proxy_pass http://app;
proxy_http_version 1.1;
set $connection_upgrade "";
if ($http_upgrade = "websocket") {
set $connection_upgrade "upgrade";
}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
这样,非 WebSocket 请求不会带上 Connection: upgrade,避免误导后端。
8. 总结 Checklist
配置 Nginx 代理 WebSocket 时,请确认以下要点全部到位:
-
proxy_http_version 1.1;已启用 -
Upgrade头透传为$http_upgrade -
Connection头显式设置为"upgrade"(小写) -
Host头透传为$host - 真实 IP 和协议信息通过
X-Real-IP、X-Forwarded-For、X-Forwarded-Proto传递 - 超时时间根据业务场景调大,避免长连接被误断
- 若需要低延迟实时推送,建议关闭代理缓冲 (
proxy_buffering off)
按照上述模板配置,即可稳定代理 WebSocket 连接,并为后端提供完整的客户端连接信息。