WebSocket连接不上?Nginx反向代理配置解析

WebSocket连接不上?Nginx反向代理配置解析

你写了一个聊天室,用WebSocket。本地测试,没问题。部署到服务器,Nginx代理转发,连不上了。浏览器报错:WebSocket connection failed,或者连上一会儿就断。

Nginx默认配置是为HTTP设计的,短连接、短超时。WebSocket是长连接,需要升级协议、保持连接不断。改几个参数就能解决。

今天把Nginx代理WebSocket的配置拆开讲清楚。


先看一个数据

根据WebSocket协议设计,连接建立时的HTTP请求头里必须包含两个特殊字段:Upgrade: websocketConnection: Upgrade。这是从HTTP升级到WebSocket的标准流程。如果Nginx没有正确传递这些头,WebSocket握手就直接失败。

实际生产环境中,超过一半的WebSocket连接问题与反向代理配置有关,而非后端服务本身。


WebSocket与HTTP的区别

HTTP:客户端请求,服务器响应。连接断开。下一次请求,重新连接。

WebSocket:客户端发起一次握手后,连接保持打开。双方可以随时互相发送消息,直到一方主动关闭。

Nginx处理HTTP很擅长,请求来了,响应回去,关闭连接。但WebSocket要求Nginx保持连接长时间不断开,并且要识别升级请求,在两端的TCP连接之间双向转发数据。

普通HTTP反向代理配置,碰上WebSocket,会不识别Upgrade头,直接断开连接。


基础配置

先看一个完整的WebSocket代理配置:

nginx

upstream websocket {
    server 127.0.0.1:8080;
    keepalive 16;
}

server {
    listen 80;
    server_name ws.example.com;

    location /ws/ {
        proxy_pass http://websocket;
        
        # WebSocket 必需的请求头
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 超时设置(关键)
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        
        # 其他常用头
        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_http_version 1.1
WebSocket要求HTTP/1.1或更高。Nginx默认用1.0。没这一行,握手直接失败。

proxy_set_header Upgrade $http_upgrade
把客户端请求里的Upgrade: websocket头原样传给后端。Nginx默认不会传这个头。

proxy_set_header Connection "upgrade"
告诉后端“这个连接要从HTTP升级成WebSocket”。Connection头的值是固定的upgrade

这三行是最小配置集。缺少任何一行,WebSocket都连不上。


超时设置

WebSocket连接建立后,可能会长时间没有任何数据传输,比如用户在看屏幕但没打字。Nginx默认超时60秒,没数据就断开。

proxy_read_timeout 3600s
从后端读取数据的超时时间,设为1小时。WebSocket长连接场景,设长一些。

proxy_send_timeout 3600s
向后端发送数据的超时时间,同样设长。

不设的话,连接静默一分钟就被Nginx切断了。客户端必须自动重连,或者用户再发一条消息时发现连不上,体验极差。


负载均衡

WebSocket支持负载均衡,但有个限制:同一个用户的连接必须一直落在同一台后端服务器上。否则消息路由会错乱。

ip_hashsticky保持会话:

nginx

upstream websocket {
    ip_hash;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    keepalive 16;
}

ip_hash根据客户端IP分配后端,同一IP的请求固定发到同一台后端。不适用共享出口IP的大型网络,但大部分情况够用。


子协议配置

如果WebSocket使用了子协议(如graphql-ws),需要额外处理请求头中的Sec-WebSocket-Protocol字段:

nginx

proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;

部分后端依赖这个字段来决定使用哪个子协议,不传递可能导致协议协商失败。


日志排查

配置好了还是连不上,看Nginx日志:

bash

tail -f /var/log/nginx/error.log
tail -f /var/log/nginx/access.log

常见错误及含义

  • upstream timed out:后端没响应,检查后端服务是否正常运行
  • no live upstreams:所有后端都挂了,健康检查失败
  • 连接后立即关闭:超时设置太短,或Upgrade头没传过去

用浏览器开发者工具的Network标签页查看WebSocket握手请求的Response Headers。如果Upgrade头没正确返回,问题大概率在Nginx。


真实案例

一个在线客服系统,用户发消息偶尔收不到。排查发现,Nginx的proxy_read_timeout默认60秒,客服人员有时需要看用户输入超过一分钟,连接就被切断了。用户继续打字时才发现连不上,重新连接后历史消息丢失。

超时改成3600秒后,问题消失。用户长时间不说话,连接也保持着。客服说:“终于不用每半分钟担心断线了。”


高级优化

TLS/SSL:WebSocket over WSS(加密WebSocket)和HTTPS代理配置几乎一样,把listen 443 ssl加上证书即可。注意确保后端能处理WSS,或让Nginx终止SSL后转发普通WS给后端。

缓冲区调优

nginx

proxy_buffering off;

WebSocket场景建议关闭缓冲,实时转发数据。开启缓冲可能导致延迟增加。


最后一句

WebSocket代理的关键就三行:proxy_http_version 1.1proxy_set_header Upgrade $http_upgradeproxy_set_header Connection "upgrade"。加上合理的超时,其他和普通HTTP反向代理配置差别不大。

如果还不行,去检查一下日志。Nginx会告诉你问题在哪。

下次WebSocket连不上,第一反应不是怀疑代码,先去检查Nginx配置。这三行写对了,90%的问题就解决了。

知识库

Docker网络模式详解:bridge、host、none怎么选?

2026-6-1 17:57:44

知识库

服务器被入侵后怎么溯源?日志分析实战技巧

2026-6-2 18:24:30

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧