Nginx 代理 WebSocket 要配 header

FreeGuideOnline 最新 2026-07-04

Nginx 代理 WebSocket 必配的 Header 详解

WebSocket 协议从 HTTP 握手升级而来,Nginx 作为反向代理时需要显式传递升级相关的头部,否则连接会降级为普通 HTTP 或直接失败。本篇将系统梳理 Nginx 代理 WebSocket 时必须配置的 header,并给出可直接用于生产环境的配置片段。

1. WebSocket 升级握手的关键 Header

客户端发起 WebSocket 连接时,会发送以下关键请求头:

  • Connection: Upgrade – 告知服务器本次连接需要升级协议
  • Upgrade: websocket – 指定升级后的协议为 WebSocket
  • Sec-WebSocket-Key – 用于握手的安全密钥
  • Sec-WebSocket-Version – 协议版本

当 Nginx 作为反向代理时,默认不会逐跳传递 ConnectionUpgrade 头。因为它们是逐跳头(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-IPX-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-IPX-Forwarded-ForX-Forwarded-Proto 传递
  • 超时时间根据业务场景调大,避免长连接被误断
  • 若需要低延迟实时推送,建议关闭代理缓冲 (proxy_buffering off)

按照上述模板配置,即可稳定代理 WebSocket 连接,并为后端提供完整的客户端连接信息。