从公网访问内网部署的服务有很多方式,比如以花生壳为代表的商业内网穿透服务,要么收费,免费的速度慢操作麻烦。本文尝试用开源的ngrok服务,自己在ubuntu16.04搭建代理转接服务器,将外网的请求转接到内网,实现从公网无障碍高速访问内网服务。大概步骤也比较简单(4步):1、在公网主机上(我用的阿里云)部署ngrok源码;2、生成证书;3、编译生成主机服务(最终生成二进制文件ngrokd,启动跑在公网主机上);4、编译生成客户端服务(最终生成二进制文件ngrok,要从公网主机复制到内网真正提供服务的主机上,并启动)。ngrok服务器,实现内网穿透的本质,就是部署在公网端的ngrokd服务和部署在客户端的ngrok服务相互通信转发指令和数据。详细部署过程:
安装go 1.8(公网主机)
ngrok是用golang写的, 搭建ngnork需要安装较高版本的go开发运行包。我开始弄的时候直接用“apt-get install golang” 安装,结果因为go的版本问题导致编译失败,最后经过测试go1.8顺利通过。步骤:
1、将压缩包下载到指定的目录
wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz
2、解压(会解压出go文件夹),记住解压出的go目录,下一步将这个目录配到/etc/profile中
tar -zxvf go1.8.linux-amd64.tar.gz
3、配置全局环境变量
sudo vim /etc/profile
#末尾添加:
export GOROOT=/usr/local/go #这个目录就是解压出来的go目录,根据自己的实际情况配置
export GOPATH=$GOROOT/bin
export PATH=$PATH:$GOPATH
4、立即生效
source /etc/profile
5、查看安装的go版本
go version
至此,go 1.8安装成功。
安装ngrok(公网主机)
1、下载ngrok源码
#下载源码到指定的目录(我的是在/usr/local/)
wget htps://coding.net/u/sfantree/p/self_use_OSS/git/raw/master/source/ngrok.tar.gz
#解压出ngrok目录
tar zxvf ngrok.tar.gz
#进入ngrok目录
cd ngrok #下面的操作步骤直到make服务端和make客户端都是在这个目录下
2、生成签名证书
使用ngrok.com官方服务时,我们使用的是官方的SSL证书。自建ngrokd服务,我们需要生成自己的证书,并提供携带该证书的ngrok客户端。
证书生成过程需要一个NGROK_BASE_DOMAIN(公网主机的域名)。如果你要提供转接服务的公网主机的地址为”xxxx.com”,那NGROK_BASE_DOMAIN就应该 是”xxxx.com”。就假设我的阿里云服务器域名是xxxx.com。如果没有域名是不是可以用公网的ip地址代替这个我没有测试过,你们可以试一下。生成证书的命令如下:
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=xxxx.com" -days 5000 -out rootCA.pem #xxxx.com是公网主机域名
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=xxxx.com" -out device.csr #xxxx.com是公网主机域名
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000
执行完以上命令,在ngrok目录下会生成6个新的文件
device.crt device.csr device.key
rootCA.key rootCA.pem rootCA.srl
3、替换证书
ngrok通过bindata将ngrok源码目录下的assets目录(资源文件)打包到可执行文件(ngrokd和ngrok)中 去,assets/client/tls和assets/server/tls下分别存放着用于ngrok和ngrokd的默认证书文件,我们需要将它们替换成我们自己生成的:(因此这一步务必放在编译可执行文件之前)
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt
cp device.key assets/server/tls/snakeoil.key
4、编译ngrokd(服务端)和ngrok(客户端)
(1)服务端(公网主机端):
make release-server
到了这一步,当我满心欢喜以为要成功的时候,报异常了,编译失败:
经过一番查找发现问题在于:go-bindata被安装到了$GOPATH(前面安装go时配到/etc/profile里面)目录,go编译器找不到了。修正方法是将$GOPATH/go-bindata拷贝到当前ngrok/bin下(没有bin目录就创建一个)。一旦出现其他原因的编译失败,注意看日志的异常信息,很多都是go的安装问题。
#我的安装目录下执行如下命令
cp /usr/local/go/bin/go-bindata /usr/local/ngrok/bin
再次执行make release-server,很幸运成功了,在/usr/local/ngrok/bin下生成ngrokd文件(原文说是/usr/local/go/bin下,反正我的不是)。
(2)客户端(真正提供服务的内网主机端,注意我的内网主机也是ubuntu,所以这样生成,如果是windows或者mac系统ngrok文件生成方法不一样的,这里就不详述):
make release-client
这次一次性成功,在/usr/local/ngrok/bin下生成ngrokd文件(客户端运行文件,要拷贝到内网服务主机上运行的)。
5、运行调试
(1)启动ngrokd服务(公网主机端)
cd /usr/local/go/bin #不是~/ngrok/bin
ngrokd -domain="xxxx.com" -httpAddr=":8088" -httpsAddr=":8089" > log.out &
#xxxx.com是公网主机域名,httpAddr和httpsAddr是外网访问的端口,&是后台运行
启动成功日志:
浏览器打xxxx.com:8088返回结果
出现Tunnel xxxx.com:8088 not found,说明公网转接服务启动成功。8088端口是启动的时候自定义的。
(2)启动ngrok客户端服务(内网真正提供服务的主机端,仅限客户端为linux)
ngrok文件在公网主机/usr/local/ngrok/bin目录下生成的,所以要从这个目录拷贝到内网主机上去,注意,我的内网主机和公网主机都是ubuntu所以直接scp命令拷过去就行了(其他客户端操作系统ngrok文件的生成方法不一样),然后需要自己写一个配置文件命名为ngrok.cfg,并和ngrok文件放在同一目录下。
ngrok.cfg配置文件内容:
server_addr: "xxxx.com:4443" # xxxx.com是公网主机的域名,4443是公网主机默认的端口不要改动
trust_host_root_certs: false
在内网主机上进行如下操作,启动ngrok:
./ngrok -subdomain pub -proto=http -config=ngrok.cfg 9002
# -subdomain是子域名,这里取pub,那么在浏览器访问时打入pub.xxxx.com:8088,9002是真正提供服务的端口根据自己的服务定
# ngrok.cfg就是制定配置文件
成功启动日志如下:
至此,Tunnel Status出现online说明客户端和公网主机服务连接成功,在浏览器访问pub.xxxx.com:8088就能访问到内网主机9002端口提供的服务。
分析:如果启动失败(非online状态,比如一直connecting或者reconnecting),首先打开公网主机端的日志(我这里输出到log.out里,直接tailf log.out)看看启动时有没有连接日志产生,如果没有说明网路连接不通,有可能是公网主机4443端口被限制了(云服务提供商安全规则要允许4443,防火墙规则也要允许4443)。也有可能是pub.xxxx.com域名解析失败,自己ping pub.xxxx.com 看看是不是0解析到你的公网主机ip上。
最后祝大家一次性成功!
有疑问加站长微信联系(非本文作者)