Nginx反向代理WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。该协议使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。如此强大的协议,从1.3.13版本开始,nginx添加对webdocket反向代理支持,让我们的websocket处理能力大大提升。

nginx配置

nginx.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
worker_processes auto;

error_log /var/log/nginx/error.log info;

events {
    worker_connections  1024;
}

# 简单示例
http {
    upstream backend {
        server 127.0.0.1:8000;
    }

    location /chat/ {
        proxy_pass http://backend;

        # 主要websocket代理配置, $http_upgrade是指http协议头部Upgrade的值. 
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

复杂示例

由于Connection协议头的值取决于Upgrade的值,我们可以利用map模块,动态生成Connection头的值,配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
http {

    upstream backend {
        server 127.0.0.1:8000;
    }

    # map指令的含义,根据$http_upgrade不同值来对$connection_upgrade变量进行赋值,默认为upgrade;$connection_upgrade可以再后续配置中进行引用即可;
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {

        location /chat/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

经过以上简单的配置,nginx -s reload后,nginx即可作为websocket反向代理服务器。这段配置的关键在于server配置段中的proxy_http_version、proxy_set_header指令,分别设置http_veresion、Upgrade、Connection头部,从而实现http到webdocket的升级。

超时参数

proxy_send_timeout time 默认值 60s 上下文 http server location 说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。 如果超时后,upstream没有收到新的数据,nginx会关闭连接

/etc/nginx/conf.d/websocket.conf

 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
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server localhost:8282; # appserver_ip:ws_port
}

server {
     server_name test.enzhico.net;
     listen 443 ssl;
     location / {
         proxy_pass http://websocket;
         proxy_read_timeout 300s;
         proxy_send_timeout 300s;
         
         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;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection $connection_upgrade;
     }
    ssl_certificate /etc/letsencrypt/live/test.enzhico.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.enzhico.net/privkey.pem;
}

nginx配置文件详解, 见nginx反向代理WebSocket

map值映射

1
2
3
4
5
map $http_upgrade $connection_upgrade {
          default upgrade;
          '' close;
}

表示的是: 如果 $http_upgrade 不为 '’ (空),则 $connection_upgrade 为 upgrade 。 如果 $http_upgrade 为 '’ (空),则 $connection_upgrade 为 close。

参考