通过nginx转发实现wss(websocket ssl)

WebSocket建立流程其实是:

Client
  │
  │ HTTP GET + Upgrade: websocket
  ▼
Nginx
  │
  │ HTTP/1.1 + Upgrade
  ▼
Backend WS Server

必须满足三个条件:

1.1HTTP/1.1

WebSocket 升级只在 HTTP/1.1 工作

proxy_http_version 1.1;

1.2Upgrade Header

客户端:

Upgrade: websocket
Connection: Upgrade

Nginx必须转发:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

你用了标准写法:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

这是 官方推荐写法


1.3长连接超时

WebSocket不是短连接。
默认 nginx:

proxy_read_timeout 60s

如果 60 秒没数据就断。
你设置:

proxy_read_timeout 300s;
proxy_send_timeout 300s;

5分钟 不过生产环境一般会更长。


二、配置文件优化

2.1upstream 建议加 keepalive

upstream ws {
    server 172.x:8081;
    keepalive 64;
}

这样 nginx 到后端不会频繁建 TCP。


2.2建议增加 Host 头

否则有些 WS 框架会校验 Host。

proxy_set_header Host $host;

2.3 建议增加 X-Forwarded-For

方便日志和风控。

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

2.4 建议关闭 proxy_buffering

WebSocket不需要buffer。

proxy_buffering off;

否则会增加延迟。


三、推荐生产版配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

upstream ws {
server X:8081;
keepalive 75;
}

server {
listen 8443 ssl;
server_name xxx.com;

ssl_certificate /etc/nginx/keys/xxx.com.pem;
ssl_certificate_key /etc/nginx/keys/xxx.com.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;

ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;

location / {

proxy_pass http://ws;
proxy_http_version 1.1;

proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

proxy_buffering off;
}
}

四、WebSocket完整流转架构

flowchart LR

A[Client Browser / App] -->|wss| B[Nginx 8443]

B -->|Upgrade websocket| C[Backend WS Service]

C --> D[业务服务]

B -.日志.-> E[ELK]

五、踩坑的点

你现在:

listen 8443 ssl http2;

HTTP/2 不支持 WebSocket Upgrade。但 nginx 会自动降级为 HTTP/1.1,所以通常 没问题。如果遇到 websocket handshake 失败,可以改成:

listen 8443 ssl;