NGINX WebSocket 代理配置实战:解决实时通信连接断开与握手失败

主题: nginx-proxy-pass-websocket-upgrade更新于: 2026/7/22作者:AgentFactory 技术团队

快速答案

  • 核心结论:NGINX 作为 WebSocket 反向代理需要显式配置 proxy_http_version 1.1proxy_set_header Upgrade $http_upgradeproxy_set_header Connection "upgrade" 三个关键指令,缺一不可。
  • 第一排查点:WebSocket 连接 60 秒断开是 proxy_read_timeout 默认值导致,需设置为 86400s;握手返回 400 错误通常因 HTTP 版本或 Upgrade 头未正确转发。
  • 最小配置:在 location 块中添加 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400s; proxy_send_timeout 86400s;
  • 适用环境:NGINX 1.3+ 版本原生支持 WebSocket 代理,适用于任何需要 NGINX 前置代理 WebSocket 后端的场景(Node.js、Python FastAPI、Go 等)。

它解决什么问题

WebSocket 协议要求从 HTTP 升级到 WebSocket 连接,而 NGINX 默认的 HTTP 代理行为会丢弃 UpgradeConnection 头,导致握手失败。本配置解决以下核心问题:

  • 握手失败:客户端收到 400 Bad Request426 Upgrade Required 响应
  • 连接意外断开:WebSocket 连接在空闲 60 秒后被 NGINX 强制关闭
  • 负载均衡兼容:在多个后端实例间正确路由 WebSocket 流量并保持会话

典型应用场景包括在线聊天系统、实时协作编辑、股票行情推送、游戏服务器、物联网设备状态监控等需要双向实时通信的系统。

安装与快速上手

安装 NGINX

BASH
# CentOS/RHEL/Fedora
dnf install nginx && systemctl enable --now nginx

# Ubuntu/Debian
apt update && apt install nginx -y && systemctl enable --now nginx

最小可用配置

以下配置实现 WebSocket 代理到本地 3000 端口的后端服务:

NGINX
http {
    # 定义后端服务器组
    upstream websocket_backend {
        server 127.0.0.1:3000;
    }

    server {
        listen 80;
        server_name example.com;

        location /ws/ {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;          # 必须:使用 HTTP/1.1
            proxy_set_header Upgrade $http_upgrade;  # 必须:转发 Upgrade 头
            proxy_set_header Connection "upgrade";   # 必须:设置 Connection 为 upgrade
            proxy_read_timeout 86400s;       # 推荐:24小时超时
            proxy_send_timeout 86400s;       # 推荐:24小时超时
            proxy_buffering off;             # 推荐:关闭缓冲
        }
    }
}

核心配置参数详解

参数必需默认值说明
proxy_http_version 1.11.0HTTP/1.1 是 WebSocket 升级的前提条件,HTTP/1.0 不支持 Upgrade 机制
proxy_set_header Upgrade $http_upgrade将客户端的 Upgrade: websocket 头原样转发给后端
proxy_set_header Connection "upgrade"对于 WebSocket 请求,将 Connection 头设置为 upgrade;非 WebSocket 请求保持原值
proxy_read_timeout60s两次读取操作之间的最大空闲时间,WebSocket 长连接建议设为 86400s
proxy_send_timeout60s两次发送操作之间的最大空闲时间,与 proxy_read_timeout 同步设置
proxy_buffering off推荐on关闭缓冲确保 WebSocket 数据实时转发,避免数据延迟

智能处理非 WebSocket 请求

使用 map 指令避免破坏普通 HTTP 请求的 Connection 头:

NGINX
http {
    map $http_upgrade $connection_upgrade {
        default  "upgrade";
        ''       "";
    }

    server {
        location /ws/ {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 86400s;
            proxy_send_timeout 86400s;
            proxy_buffering off;
        }
    }
}

当客户端不发送 Upgrade 头时(普通 HTTP 请求),$connection_upgrade 变量为空字符串,Connection 头不会被错误设置为 upgrade

与同类方案对比

对比维度NGINXCaddyHAProxy专用 WebSocket 代理
配置复杂度中等,需手动处理 Upgrade 头低,自动处理 WebSocket 升级中等,需配置 TCP 模式低,功能单一
高并发性能优秀,事件驱动模型良好极佳,纯 TCP 代理延迟最低一般
功能丰富度高,支持 HTTP/2、gRPC、缓存、限流中,自动 HTTPS 是亮点中,侧重 TCP/HTTP 负载均衡低,仅 WebSocket
生态成熟度极高,文档和社区支持最完善中等,增长迅速高,生产验证充分
安全特性内置限流、WAF 集成、访问控制自动 HTTPS、ACME 集成基础 ACL、TLS 终止有限

亮点:NGINX 通过 map 变量智能处理 Connection 头,这是其他方案常忽略的细节,能避免破坏非 WebSocket 请求。

生产环境实践与注意事项

性能调优

NGINX
events {
    worker_connections 10240;          # 提高并发连接数
    use epoll;                         # Linux 下使用 epoll
    multi_accept on;                   # 一次接受所有新连接
}

http {
    # 调整文件描述符限制
    worker_rlimit_nofile 65535;
    
    # 关闭缓冲
    proxy_buffering off;
    proxy_request_buffering off;
    
    # 超时设置
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
}

负载均衡与会话保持

NGINX
upstream websocket_backend {
    ip_hash;                           # 基于 IP 哈希实现会话保持
    server 192.168.1.1:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.2:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.3:3000 backup;   # 备用服务器
}

ip_hash 确保同一客户端始终路由到同一后端,避免 WebSocket 会话状态丢失。如果后端是无状态设计,可使用轮询配合 Redis 共享会话存储。

安全加固

NGINX
location /ws/ {
    # 限制来源
    valid_referers none blocked server_names *.example.com;
    if ($invalid_referer) {
        return 403;
    }
    
    # 限流防止洪水攻击
    limit_req zone=websocket burst=20 nodelay;
    limit_conn websocket 10;
    
    # 仅允许 WebSocket 升级请求
    if ($http_upgrade !~* "websocket") {
        return 400;
    }
    
    proxy_pass http://websocket_backend;
    # ... 其他配置
}

日志优化

WebSocket 连接关闭会产生大量无意义日志,建议调整日志级别:

NGINX
http {
    # 仅记录错误级别日志
    error_log /var/log/nginx/error.log error;
    
    # 或使用条件日志
    map $status $loggable {
        ~^[23]  0;  # 2xx 和 3xx 不记录
        default 1;
    }
    access_log /var/log/nginx/access.log combined if=$loggable;
}

常见报错与排查

错误 1:WebSocket 握手返回 400

报错信息WebSocket connection to 'wss://example.com/ws/' failed: Error during WebSocket handshake: Unexpected response code: 400

排查步骤

  1. 检查 proxy_http_version 是否设置为 1.1
  2. 确认 proxy_set_header Upgrade $http_upgradeproxy_set_header Connection "upgrade" 已正确配置
  3. 验证后端服务是否在监听正确的端口和路径
  4. 查看 NGINX 错误日志:tail -f /var/log/nginx/error.log

错误 2:上游连接被提前关闭

报错信息upstream prematurely closed connection while reading upstream

解决方案

  1. 增加超时值:proxy_read_timeout 86400s; proxy_send_timeout 86400s;
  2. 检查后端 WebSocket 服务是否因空闲超时主动断开连接
  3. 在后端实现心跳机制(ping/pong 帧)
  4. 考虑添加 proxy_ignore_client_abort on;

错误 3:无可用上游服务器

报错信息no live upstreams while connecting to upstream

排查步骤

  1. 检查 upstream 块中定义的后端服务器是否健康
  2. 确认后端服务正在运行且端口可访问:curl http://127.0.0.1:3000/ws/
  3. 检查防火墙规则是否阻止了 NGINX 到后端的连接
  4. 使用 backup 标记配置备用服务器

错误 4:SSL 握手失败

报错信息SSL: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

解决方案

  1. 确认 SSL 证书和密钥文件路径正确且权限为 600
  2. 检查 ssl_protocols 是否包含后端支持的 TLS 版本
  3. 验证证书链是否完整(包括中间证书)
  4. 使用 openssl s_client -connect backend:port 测试后端 SSL 配置

常见问题 FAQ

Q: 为什么我的 WebSocket 连接在 60 秒后自动断开?

A: 这是 NGINX 默认的 proxy_read_timeoutproxy_send_timeout(均为 60 秒)导致的。WebSocket 连接空闲时,NGINX 会关闭超过 60 秒无数据传输的连接。解决方案:在 location 块中设置 proxy_read_timeout 86400s;proxy_send_timeout 86400s;(24 小时)。注意:这些超时是两次操作之间的间隔,如果 WebSocket 定期发送心跳消息,超时会被重置。建议同时在后端实现 WebSocket 心跳机制(ping/pong 帧),保持连接活跃。

Q: NGINX WebSocket 代理如何实现负载均衡和会话保持?

A: NGINX 支持多种负载均衡算法:1) 轮询(默认):upstream websocket_backend { server 192.168.1.1:3000; server 192.168.1.2:3000; };2) IP 哈希(会话保持):upstream websocket_backend { ip_hash; server ...; };3) 最少连接:upstream websocket_backend { least_conn; server ...; }。对于 WebSocket,推荐使用 ip_hash 确保同一客户端的请求始终路由到同一后端,避免会话状态丢失。注意:如果后端是无状态设计,可以使用轮询配合后端共享会话存储(如 Redis)。

Q: 如何调试 NGINX WebSocket 代理的连接问题?

A: 1) 启用调试日志:在 events 块中添加 debug_connection [客户端IP];在 http 块中添加 error_log /var/log/nginx/error.log debug;;2) 使用 curl 测试 WebSocket 握手:curl -v -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" http://example.com/ws/;3) 检查后端响应:确保后端返回 101 Switching Protocols 状态码;4) 使用 tcpdump 抓包分析:tcpdump -i any port 80 or port 443 -w websocket.pcap;5) 验证 NGINX 配置:nginx -t 检查语法,nginx -T 输出完整配置。

相关深度解决方案

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 Nginx 上游连接提前关闭错误排查与修复:proxy_read_timeout 与缓冲区配置

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 Nginx 413 Request Entity Too Large 错误:client_max_body_size 配置与排查