Nginx代理WebSocket

Nginx代理WebSocket

引言

聊天、实时推送、在线协作这类场景用WebSocket长连接。前端经过Nginx访问后端WS服务时,如果只按普通HTTP反代配置,握手会失败,因为WebSocket要先发起Upgrade协议升级,Nginx必须把升级头透传给后端。

WebSocket握手原理

客户端先发HTTP请求,带Upgrade: websocket和Connection: Upgrade头,后端同意后把HTTP协议升级成持久双向长连接。Nginx默认不透传这两个头,导致握手400。

标准代理配置

location /ws/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 3600s;
}
  • proxy_http_version 1.1:WS基于HTTP/1.1;
  • Upgrade $http_upgrade:透传客户端升级协议;
  • Connection "upgrade":标记连接升级;
  • read_timeout拉长:长连接默认60秒无数据会被Nginx断开。

用map统一处理

不同location可能同时有HTTP和WS,写map避免硬编码:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
# location内
proxy_set_header Connection $connection_upgrade;

普通HTTP请求$http_upgrade为空时走close,WS请求走upgrade,一套配置兼容。

常见问题

  • 握手400/502:没加Upgrade和Connection头;
  • 连接几十秒自动断开:read_timeout太短,按需拉长或服务端发心跳;
  • wss(HTTPS)走Nginx终止TLS后,后端用ws即可;
  • 后端端口和proxy_pass写对,别漏http://。

注意事项

  • 长连接超时靠心跳和read_timeout共同维持;
  • 集群WS要配合粘性会话或后端共享状态,否则消息发不到正确连接;
  • HTTPS页面必须用wss://,浏览器会拦截混合内容;
  • 改配置nginx -t后reload。

总结

Nginx代理WebSocket核心是加proxy_http_version 1.1、透传Upgrade和Connection头、拉长read_timeout,用map兼容普通HTTP。握手失败先查这三个头,断线先查超时和心跳。


emer 发布于  2026-10-19 07:22