Nginx 如何反向代理 WebSocket 并启用 SSL(wss://)?

Nginx 反代 WebSocket + WSS 完整配置:Upgrade/Connection 头映射、SSL 证书、proxy_read_timeout 防连接被掐、心跳建议与 FAQ。

最佳实践
Nginx 如何反向代理 WebSocket 并启用 SSL(wss://)?封面

WebSocket 反代的关键是三行:proxy_http_version 1.1 + 两个升级头(Upgrade/Connection)。启用 wss 则像普通 HTTPS 站点一样给 Nginx 配证书——客户端到 Nginx 走 wss,Nginx 到后端可走 ws 或 wss。

完整配置

# http 块:Connection 头的智能映射(普通请求不带 Upgrade 时保持空值)
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl;
    server_name ws.example.com;

    ssl_certificate     /etc/nginx/ssl/ws.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/ws.example.com.key;

    location /ws/ {
        proxy_pass http://backend:8080;

        # WebSocket 三要素
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $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;

        # 防长连接被闲置超时掐断(默认 60s)
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

逐点解释

  • Upgrade + Connection:WebSocket 靠 HTTP 握手里的这两个头完成协议升级;Nginx 默认不带它们转发,握手必然失败(客户端报 400/426 或静默断开)。map 的作用是:只在客户端真的带 Upgrade 时才回 Connection: upgrade,避免污染普通请求。
  • proxy_http_version 1.1:WebSocket 要求 HTTP/1.1,而 Nginx 反代默认用 1.0——漏了这行同样握手失败。
  • proxy_read_timeout:默认 60 秒没有数据就断连——对聊天室这种"安静期很长"的应用是灾难。调大,并由应用层心跳(ping/pong)配合保活。
  • wss 终止在 Nginx:客户端↔Nginx 加密(wss://),Nginx↔后端内网可走明文 ws://;跨不可信网段时后端也上 TLS(proxy_pass https://...)。

验证

# 命令行握手测试
curl -i -N \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
  https://ws.example.com/ws/
# 期望返回 101 Switching Protocols

观测云对照

WebSocket 服务的健康度靠传统"请求成功率"看不出来——连接数、断连率、消息延迟才是核心指标。后端应用接入观测云 APM/RUM 暴露连接数指标,Nginx 访问日志采集后,对 101 握手成功率、异常断连(499/502)设告警,"用户大面积掉线"能在工单涌进来之前被发现。

常见问题(FAQ)

Q:客户端报 400 或握手后立即断开?
A:九成是 Upgrade/Connection 头没转发。按上面的三要素配置检查,特别是用了 map 之后别忘了 Connection $connection_upgrade

Q:连接建立后固定 60 秒就断?
A:proxy_read_timeout 默认值。调大它,并且应用层实现 WebSocket ping/pong 心跳(30 秒一次较常见),双保险。

Q:负载均衡多个 WebSocket 后端要注意什么?
A:WebSocket 是有状态长连接,要么用 ip_hash 保持会话粘滞,要么应用层用 Redis Pub/Sub 等做跨节点消息同步。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台