Nginx代理WebSocket需精确路径匹配与协议升级头透传:用location ~ ^/ws/ 匹配路径,proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade 和 Connection "upgrade" 必须配置,proxy_pass末尾斜杠决定路径是否剥离,proxy_read_timeout建议设为86400。

Nginx 代理 WebSocket 时,若需支持特定路径(比如 /ws/app1、/ws/v2/chat),不能只靠简单前缀匹配(如 location /ws { }),否则子路径会被截断、后端无法识别路由,导致握手失败或 404。关键在于路径透传 + 协议升级头正确转发。
必须启用 HTTP/1.1 并透传升级头部
WebSocket 握手依赖标准的 HTTP 升级机制,Nginx 必须显式传递 Upgrade 和 Connection 头,并强制使用 HTTP/1.1:
-
proxy_http_version 1.1是硬性要求,HTTP/1.0 不支持长连接与协议升级 -
proxy_set_header Upgrade $http_upgrade将客户端原始 Upgrade 头(通常是"websocket")原样传递 -
proxy_set_header Connection "upgrade"不要用$connection_upgrade变量,除非你已定义 map 块;直接写"upgrade"更稳妥、兼容性更好
使用正则 location 精确匹配路径前缀
用 location ~ ^/ws/ 替代 location /ws,避免前缀匹配误伤其他 /wsxxx 路径,同时为后续路径重写留出空间:
-
^/ws/表示以/ws/开头的完整路径,如/ws/app1、/ws/v2/chat都能命中 - 不加
^可能匹配到/websocket/等干扰路径;不加结尾/则/ws(无斜杠)也会被匹配,易引发歧义
路径是否带尾 / 取决于后端期望
proxy_pass 的末尾斜杠决定路径如何转发:
-
proxy_pass http://backend:8080;→ 客户端请求/ws/app1,后端收到/ws/app1 -
proxy_pass http://backend:8080/;→ 同样请求,后端收到/app1(/ws被剥离) -
proxy_pass http://backend:8080/ws/;→ 后端收到/ws/app1(仅当后端监听/ws/下路由时才需这样写)
多数现代 WebSocket 框架(如 Spring WebFlux、FastAPI WebSocketRouter)默认按完整路径路由,建议保留原始路径,即 proxy_pass http://backend:8080;
设置足够长的空闲超时
WebSocket 是长连接,Nginx 默认 60 秒超时会主动断开:
-
proxy_read_timeout 86400;(24 小时)是常见安全值,可根据业务最长空闲时间调整 -
proxy_send_timeout可设相同值,避免单向阻塞导致连接中断 - 不建议关闭 timeout,否则可能积累大量僵死连接
完整可复用配置示例
upstream ws_backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name example.com;
location ~ ^/ws/ {
proxy_pass http://ws_backend;
proxy_http_version 1.1;
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 86400;
proxy_send_timeout 86400;
}
location / {
root /var/www/html;
index index.html;
}
}不复杂但容易忽略


















