使用docker和wstun实现隧道和反向隧道
需求及方案确定
这次的需求是因为一个服务器的网络配置有问题,只能走WEB接入,不能访问外网,但是应用又需要访问第三方的服务,被迫寻找解决方案。
因为只能走WEB(这里是Nginx代理的HTTPS),所以唯一的方法就是WebSocket,好在WebSocket代理工具还挺多,但是具体到这种需要反向隧道的情况,目前只找到MDSLab的wstun,一个基于node.js实现的WSTunnel。
又因为不想装node.js,所以用了官方的docker镜像。
顺便说一句,这个解决方案感觉不错,可以用来作为一种内网穿透的工具。
系统架构
先以比较简单的正向隧道来说:
client => docker wstun client(bind client port) =Internet=> nginx => docker wstun server => server port
反向隧道其实差不多,不过需要理解一下连接和传输的方向是相反的——连接还是从客户端连到服务端,但是隧道的传输是服务端连到指定的绑定端口,然后通过隧道到达客户端的相应端口:
client port => docker wstun client =Internet=> nginx => docker wstun server(bind server port) => server
区别在于,docker wstun client建立隧道以后,是连到客户端的端口,然后docker wstun server绑定服务端的端口,把服务端发往这个端口的请求转发到客户端。
部署
由于docker的存在,所以两边的网络实际上会多一层,配置上要注意,不然很容易就配不通。
另外,官方镜像有一点比较坑的是,他们用了ENTRYPOINT,导致运行时会强制执行这个ENTRYPOINT,这里应该用CMD的。
解决方法有两个,一个是运行时加上:--entrypoint=''
,另一个是派生一个新的镜像,在Dockerfile里加上ENTRYPOINT []
。
我是用后者,所以命令里省去了--entrypoint=''
,如果用官方镜像的话,记得自己加上这个。
正向隧道
以连接服务器的SSH为例。
首先在服务端运行一个容器:
docker run -d -p 127.0.0.1:1808:1808 --name wstun_server mywstun wstun -s 1808
其中mywstun是自己派生的镜像名,后面的容器运行命令:wstun -s 1808
表示启动一个正向隧道,监听1808端口的WebSocket。
前面的参数中:127.0.0.1:1808:1808
是把容器里这个1808映射出来供Nginx代理用。
Nginx的配置如下:
# 在http段加上全局配置
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 在server段加上代理配置
location /wstun/ {
proxy_pass http://127.0.0.1:1808/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
再来配置客户端,同样是运行一个wstun容器:
docker run -d -p 127.0.0.1:2222:2222 --name wstun_client mywstun wstun -t 2222:192.168.x.x:22 https://x.x.x.x/wstun
同样用自己派生的镜像运行命令:wstun -t 2222:192.168.x.x:22 https://x.x.x.x/wstun
,其中那个URL就是nginx代理出来的WebSocket地址,-t参数则表示要建立一个隧道,从本地的2222端口到远程的192.168.x.x:22。
注意,远程的127.0.0.1并不是远程服务器,而是远程wstun容器,不要搞错了。
然后还要用docker把容器里的2222映射到客户端的127.0.0.1:2222。
现在就可以在客户机用ssh通过127.0.0.1:2222连接到远程的192.168.x.x:22了。
反向隧道
这个就是最初的需求了,把本地的HTTP代理服务器映射到服务器上供服务端上网用。
首先在客户端装一个HTTP代理服务器,比如privoxy绑定8118端口。注意:绑定地址不能为127.0.0.1,因为需要给docker wstun client访问,所以必须是本地局域网IP或用0.0.0.0。
然后在服务端运行一个容器:
docker run -d -p 127.0.0.1:1808:1808 -p 127.0.0.1:8118:8118 --name wstun_server mywstun wstun -r -s 1808
与正向隧道的配置差不多,只是多了一个-r参数。另外就是docker的参数里增加了一个8118的映射。
nginx代理配置跟正向代理一样,略过。
再看客户端的容器:
docker run -d --name wstunr_client mywstun wstun -r8118:192.168.x.x:8118 https://x.x.x.x/wstun
主要就是一个-r参数,其中192.168.x.x是本机的局域网地址,不可以用127.0.0.1,因为这个是容器内的,不会连到privoxy。
这样就建立了一个反向的隧道:
客户端容器把192.168.x.x:8118映射到远程端的8118,远程的服务端容器监听的8118被docker映射到服务器的127.0.0.1:8118,这样服务端只要使用127.0.0.1:8118做代理即可通过这个隧道转发到客户端的privoxy的8118端口,再出去互联网。
推送到[go4pro.org]