nginx配置websocket的反向代理

本文中的nginx版本:nginx/1.16.1


话不多说,直接上配置:

server
    {
        listen 80;
        server_name test.css3er.com;
        index index.html index.htm index.php;
        root  /home/wwwroot/default;
        autoindex            on;  #显示目录列表
        autoindex_exact_size on;  #显示出文件的确切大小,单位是bytes
        autoindex_localtime  on;  #显示的文件时间为文件的服务器时间

        #error_page   404   /404.html;

        # Deny access to PHP files in specific directory
        #location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

        include enable-php.conf;

        location /nginx_status
        {
            stub_status on;
            access_log   off;
        }

        # 添加websocket的反向代理配置 
	location /ws/  
	{   
     		proxy_pass http://192.168.1.101:6688/; # websocket服务器 不用管ws:// 根据自己的实际情况进行调整(这一步必须有)
     		
     		proxy_http_version 1.1; # 代理http协议的版本,因为这里是代理websocket协议,所以http协议使用1.1 用于keepalive连接 也就是保持长连接(这一步必须有)    
     		
     		proxy_set_header Upgrade "websocket"; # 表示要“升级”成websocket协议(这一步必须有)
     		# proxy_set_header Upgrade $http_upgrade; 这个和上面的proxy_set_header Upgrade "websocket";是一个意思,两个写其中一个即可   
     		
     		proxy_set_header Connection "Upgrade"; # 表示要求协议“升级”,也就是说这不是一个普通的http协议    
     		
     		# proxy_set_header X-real-ip $remote_addr; # 这个没啥好解释的(这一步可以没有)
     		
     		# proxy_set_header X-Forwarded-For $remote_addr;# 标记通过http代理或负载均衡方式连接到web服务器的客户端最原始的ip地址的http请求头字段(这一步可以没有)
     }


        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

        access_log  /home/wwwlogs/access.log;
    }

以上就完成了一个最简单最普通的nginx反向代理websocket协议的配置,使用如下(这里以javascript代码举例)

没有使用nginx反向代理之前,我们使用websocket协议需要这么连接,直接写ip+端口
var ws =  new WebSocket("ws://192.168.1.101:6688");


使用了nginx反向代理之后:
var ws =  new WebSocket("ws://test.css3er.com/ws/");

好处:假如说我们开发有测试服务器和线上正式服务器,项目在测试服和正式服之间的websocket的连接地址依然是ws://test.css3er.com/ws 如果没有使用nginx反向代理,那我们客户端的websocket连接地址在测试服的时候只能写测试服的ip+端口,项目上线的时候就要换成正式服的ip+端口。。很麻烦。。



支持跨域版:

server
    {
        listen 80;
        server_name test.css3er.com;
        index index.html index.htm index.php;
        root  /home/wwwroot/default;
        autoindex            on;  
        autoindex_exact_size on;  
        autoindex_localtime  on; 
        
         # 允许跨域相关配置
        add_header Access-Control-Allow-Origin *; # 允许跨域请求的域, *代表所有
        
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; # 允许请求的方法,如 GET/POST/OPTIONS
        
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; # 允许请求的header

        # 给OPTIONS添加204的返回,是为了处理在发送POST请求时nginx依然拒绝访问的错误 发送"预检请求"时,需要用到方法OPTIONS,所以服务器需要允许该方法
        if ($request_method = 'OPTIONS') {
            return 204;
        }

        #error_page   404   /404.html;

        # Deny access to PHP files in specific directory
        #location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

        include enable-php.conf;

        location /nginx_status
        {
            stub_status on;
            access_log   off;
        }

        # 添加websocket的反向代理配置 
	location /ws/  
	{   
     		proxy_pass http://192.168.1.101:6688/;
     		proxy_http_version 1.1;  
     		proxy_set_header Upgrade $http_upgrade; 
     		proxy_set_header Connection "Upgrade";
        }

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

        access_log  /home/wwwlogs/access.log;
    }


nginx配置了反向代理,会有几个关于超时或连接关闭的选项配置需要注意下:

proxy_connect_timeout  #与代理服务器建立连接时的超时时间。
proxy_read_timeout     #从代理服务器读取响应的超时时间,也就是在配置的时间内,代理服务器没有响应的话,则断开连接。
proxy_send_timeout     #代理服务器数据回传时间,就是在规定时间之内代理服务器必须传完所有的数据。

#以上几个配置选项的配置上下文都可以在http,server,location段内进行配置,同时,这个几个选项的默认时间都是60s(秒)


注意:我这里配置的反向代理websocket协议都是ws://(80端口),如果要配置成ssl,即wss:// 也很简单 和配置https差不多 就是一个证书的事,这里就不上demo了


默认情况下,Websocket的ws协议使用80端口。运行在TLS之上的时候,wss协议默认使用443端口。其实说白了,wss就是ws基于SSL 的安全传输,与https一样样的道理。


如果你的网站是https协议的,那你websocket连接的时候就不能使用 ws://了,浏览器会block掉连接,和https下不允许http请求一样。


websocket和http协议的相关概念补充

WebSocket和HTTP协议不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的基础设施。例如,WebSocket可以使用标准的HTTP端口 80 和 443,因此,现存的防火墙规则也同样适用。


当客户端发过来一个Connection: Upgrade请求头时,nginx是不知道的,所以,当nginx代理服务器拦截到一个客户端发来的 Upgrade请求时,需要显式来设置Connection 、Upgrade 头信息,并使用 101(交换协议)返回响应,在客户端和代理服务器、后端服务器之间建立隧道来支持WebSocket。


当然,还需要注意一下,WebSocket仍然受到nginx缺省为60秒的proxy_read_timeout的影响。这意味着,如果你有一个程序使用了 WebSocket,但又可能超过60秒不发送任何数据的话,那你要么需要增加超时时间,你可以使用proxy_read_timeout指令来增加此超时时间 。或者,每过几秒钟就让代理服务器使用websocket协议发送一个ping的消息给后端服务器,以保持他们之间的联系。使用ping的解决方法有额外的好处,可以发现连接是否被意外关闭。


更具体文档详见nginx官方文档:http://nginx.org/en/docs/http/websocket.html

nginx配置websocket协议的反向代理

nginx通过在客户端和后端服务器之间建立起一条隧道来支持websocket。为了使nginx可以将来自客户端的Upgrade请求转发给后端服务器,Upgrade和Connection的头信息必须被显式的设置。如下所示:

location /ws/ {
    proxy_pass http://wsbackend; # 这里请根据自己的实际情况进行填写
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

一旦完成以上设置,nginx就可以处理websocket连接了。

尾声:

本篇博文主要说一下在nginx中如何使用反向代理来代理WebSocket协议,并补充了一些websocket和http协议的一些基本区别。以及配合nginx使用域名方式建立连接,不使用 ip地址 + 端口号 连接 WebSocket,因为这种方式不够优雅,并且多个服务器之间进行切换的时候,客户端连接服务器时,需要改对应服务器的ip地址+端口号。



声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

精彩评论

全部回复12人评论7,777人参与