使用nginx配置WebSocket 的反向代理

简介:生产环境下WebSocket 在Ubuntu服务端使用nginx部署反向代理

WS

WS 是WebSocket 的简称,它是 HTML5一种新的协议。它实现了浏览器与服务器全双工通信,能更好地节省服务器资源和带宽并达到实时通讯。WebSocket建立在TCP之上,同HTTP一样通过TCP来传输数据,WebSocket 和HTTP协议不同是:
WebSocket是一种双向通信协议,在建立连接后,WebSocket服务器和Browser/Client Agent都能主动的向对方发送或接收数据,就像Socket一样;WebSocket需要类似TCP的客户端和服务器端通过握手连接,连接成功后才能相互通信,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的基础设施。例如,WebSocket可以使用标准的HTTP端口 80 和 443,因此,现存的防火墙规则也同样适用。

WSS

WSS 是 Web Socket Secure 的简称, 它是 WebSocket 的加密版本。 WebSocket 中的数据是不加密的, 但是不加密的数据很容易被别有用心的人窃取,因此为了保护数据安全,人们将 WebSocket 与 SSL 结合, 实现了安全的 WebSocket 通信, 即 WebSocket Secure,
所以说 WSS 是使用 SSL 进行加密了的 WebSocket 通信技术。

HTTPS

HTTPS 和 WSS 类似, HTTP 之于 HTTPS 就像 WebSocket 之于 WebSocket Secure.
HTTP 协议本身也是明文传输, 因此为了数据的安全性, 人们利用 SSL 作为加密通道, 在 SSL 之上传递 HTTP 数据, 因此 SSL 加密通道上运行的 HTTP 协议就被称为 HTTPS 了.

SSL 是基础, 在 SSL 上运行 WebSocket 协议就是 WSS; 在 SSL 上运行 HTTP 协议就是 HTTPS.

Nginx 给 WebSocket 做反向代理

一个WebSocket的应用程序会在客户端和服务端保持一个长时间工作的连接。用来将连接从HTTP升级到WebSocket的HTTP升级机制使用HTTP的Upgrade和Connection协议头。反向代理服务器在支持WebSocket方面面临着一些挑战。一项挑战是WebSocket是一个hop-by-hop协议,所以,当代理服务器拦截到一个客户端发来的Upgrade请求时,它(指服务器)需要将它自己的Upgrade请求发送给后端服务器,也包括合适的请求头。此外,由于WebSocket连接是长时间保持的,所以代理服务器需要允许这些连接处于打开状态,而不是像对待HTTP使用的短连接那样将其关闭。

-在nginx.confhttp区域内要添加下面配置:

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

map指令会获取客户端发起请求中的变量$http_upgrade的值,再根据{}中的规则创建新的变量$connection_upgrade。对{}中的规则的理解:default upgrade;其中的规则没有做匹配,因此使用默认的,即$connection_upgrade 的值会一直是 upgrade。然后如果 $http_upgrade为空字符串的话,
那值会是 close

  • 配置server区域
    NGINX 通过在客户端和后端服务器之间建立起一条隧道来支持WebSocket。为了使NGINX可以将来自客户端的Upgrade请求发送给后端服务器,Upgrade和Connection的头信息必须被显式的设置。在我的服务端配置文件的server区块添加以下:
    # 此路由为websocket服务
    location /ws/ {
        proxy_pass http://websocket_server/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }

以下为80端口完整的配置:

upstream websocket_font {
    server unix:/var/www/websocket_server/run/gunicorn.sock fail_timeout=0;
}

upstream websocket_server {
    hash $remote_addr consistent;
    server 127.0.0.1:5002;
}

server {
    listen 80; # CHAT_WS_CLIENT_PORT
    server_name localhost;   # CHAT_WS_CLIENT_HOST
    proxy_read_timeout 600;
    proxy_send_timeout 600;
    proxy_buffer_size 300k;
    proxy_buffers   4 300k;
    proxy_busy_buffers_size 300k;
    proxy_temp_file_write_size 300k;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    root /var/www/websocket_server;
    access_log /var/log/nginx/websocket_font_access.log;
    error_log /var/log/nginx/websocket_font_error.log;

    location /static {
          expires max;
          alias /var/www/websocket_server/static;
    }

    location /media  {
        alias /var/www/websocket_server/media;

    }

    # 根路由为websocket的前端示例
    location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        if (!-f $request_filename) {
            proxy_pass http://websocket_font;
            break;
        }
    }
    # 此路由为websocket服务
    location /ws/ { # CHAT_WS_CLIENT_ROUTE
        # 后面必须要带`/`
        proxy_pass http://websocket_server/;
        proxy_http_version 1.1;
        proxy_connect_timeout 10s;                #配置点1
        proxy_read_timeout 60s;                  #配置点2,如果没效,可以考虑这>个时间配置长一点
        proxy_send_timeout 12s;                  #配置点3
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
}

以上以上设置完成后,NGINX就可以处理WebSocket连接了。

WebSocket 字段说明

WebSocket是应用层协议,是TCP/IP协议的子集,通过HTTP/1.1协议的101状态码进行握手。也就是说,WebSocket协议的建立需要先借助HTTP协议,在服务器返回101状态码之后,就可以进行websocket全双工双向通信了,就没有HTTP协议什么事情了。
参照wiki握手协议的例子:并对一些字段进行说明。
896144-20171222180109631-1709435353.png

  • Connection : Connection必须设置为Upgrade,表示客户端希望连接升级

  • Upgrade : Upgrade必须设置为WebSocket,表示在取得服务器响应之后,使用HTTP升级将HTTP协议转换(升级)为WebSocket协议。

  • Sec-WebSocket-key : 随机字符串,用于验证协议是否为WebSocket协议而非HTTP协议

  • Sec-WebSocket-Version : 表示使用WebSocket的哪一个版本。

  • Sec-WebSocket-Accept : 根据Sec-WebSocket-Accept和特殊字符串计算。验证协议是否为WebSocket协议。

  • Sec-WebSocket-Location : 与Host字段对应,表示请求WebSocket协议的地址。

  • HTTP/1.1 101 Switching Protocols : 101状态码表示升级协议,在返回101状态码后,HTTP协议完成工作,转换为WebSocket协议。此时就可以进行全双工双向通信了。

WebSocket协议的浏览器兼容性较好。

推荐阅读

目录