最近在用go语言的leaf框架开发H5游戏的服务器端,用websocket的方式进行服务器与客户端之间的通讯。然后之前都是本地websocket开发,要部署到facebook平台的时候,平台要求与第三方服务器通讯需要有ssl证书。微信小程序同理。

所以决定用nginx进行反向代理,将websockets(wss)请求转发到原来服务器的websocket请求。这样可以不用修改服务器端的代码,同时后续也可以配置负载均衡的功能。

由于公司服务器还没有申请下来,ssl证书也还没申请下来,于是决定先在本地完整试验一下整个流程。

PS:本教程步骤与具体服务器语言无关

首先先在本地搭建一个测试环境:

1、下载nginx

下载地址:nginx: download  (建议下载稳定版的)

下载之后解压到某个文件夹,然后shift+右键——在此处打开控制台,输入start nginx启动服务器

在浏览器输入localhost,如果有出来nginx页面就代表成功了。

具体命令行操作可以参考这篇博客:

2、在本地生成免费的ssl证书。(如果自己公司或者自己网站有认证证书可以跳过此步)

免费SSL生成工具:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions

进去了之后下载最新的安装包安装即可,当前最新版本是  Win64 OpenSSL v1.1.0i

如果网站挂了也可以从国内的资源站下载:OpenSSL官方下载 - 码客

然后参考这篇博客生成属于自己的ssl证书:Nginx配置SSL证书部署HTTPS网站(颁发证书)

3、找到nginx配置文件

打开Nginx安装目录,找到 conf/nginx.conf 配置文件。

这个配置文件每一行代表什么意思可以参考这篇博客 

这篇博客也讲了http的反向代理,有空可以试试,没空就不用细看了。

注意,“#” 开头的一行表示配置文件的注释,不要写着写着写混了写到被注释掉的配置信息里了。

4、修改配置文件,进行websocket反向代理

在配置文件中的 http{ } (http大括号里面)中加上如下代码

# 实际websocket服务器地址
upstream wss_svr {
    server 192.168.213.182:3653 weight=1;  
}

# 443 ssl端口配置,实际websockets(wss)地址
server {

    listen 443;
    server_name 192.168.213.182;
		
    ssl on;

    # 自己的证书,放在与nginx.conf同一文件夹下。(若放不同文件夹注意路径问题)
    ssl_certificate dhxtest.crt;
    ssl_certificate_key dhxtest_nopass.key;
		
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2 SSLv3;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;
    ssl_verify_client off;
		
    location / {		
        proxy_redirect off;
        proxy_pass http://wss_svr;      # 转发
        proxy_set_header Host $host;
        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;   # 升级协议头
        proxy_set_header Connection upgrade;
    }
		
}

其中,我原来的游戏服务器是192.168.213.182:3653,而外部需要访问的地址是 192.168.213.182:443

location的proxy_pass就将wss请求转发到http://wss_svr; 也就是我原来的websocket地址 http://192.168.213.182:3653;

最后两行的set_header表示将http协议头升级为websocket协议

最后结果:访问 wss://192.168.213.182:443,nginx转发请求到 ws://192.168.213.182:3653,然后和3653端口的websocket服务进行通信

自此,Nginx反向代理完成。

5、测试配置成果

通用测试方法:

1)首先打开nginx —— 控制台输入start nginx

2)打开你原来的服务器,我的服务器是go游戏服务器,服务端口是我本机的3653端口。

3)打开chrome浏览器,打开任意页面,按F12 - console打开浏览器控制台,在控制台输入

      var wss = new WebSocket("wss://192.168.213.182:443")

      如果不报错,提示undefined,就是成功连接啦。如果你原来的服务器有连接提示,此时应该也能够看到有人连接到了你的websocket端口。

PS:此连接方法是在没有客户端的情况下测试,如果有对应客户端按原来的流程看是否正常代理了请求即可

6、可能报错

报错1:chrome浏览器提示 WebSocket connection to 'wss://192.168.213.182/' failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT ,代表根本没连接上你原来的服务器。检查一下端口是否都写对了,配置是否按上面的流程走下来了

报错2:chrome浏览器提示 NET::ERR_CERT_COMMON_NAME_INVALID ,这个是由于你的chrome浏览器识别出目标443地址的证书是自己颁发的,给你禁止了。解决办法:直接输https://你的域名,点高级-继续前往你的域名。后续即可成功连接了。

报错3:此条针对go leaf游戏服务器框架。leaf框架的websocket部分是使用到了gorilla/websocket库,连接后,gorilla/websocket报错websocket: the client is not using the websocket protocol: 。搜索这条报错的提示的地方,然后调试进gorilla/websocket库里那条报错前后对应代码,会发现header中connection部分的值为" "upgrade" ",多了一对引号,导致http协议升级ws失败。这个的原因是因为在配置文件中最后一行写成了proxy_set_header Connection "upgrade"; 很多教程都会在最后upgrade这边多一个引号,但是对于golang的gorilla/websocket库,以这种反向代理升级的方式,引号也会被引用进去,所以会报错。解决办法就是删除引号即可。