文章更新
- 20170330-初次成文
为什么会有这篇文章
我所在的公司,使用的网络是由北京联通提供的,100多台电脑共用一个公网出口IP。为了使用Resilio Sync同步我公司和家里的电脑数据,本想和网管商量下,能否给我的内网IP开设端口转发功能,无奈询问之后,网管竟然不清楚服务器和路由器的位置。这种内网环境,即便通过Shadwosocks,也经常发生内网和外部电脑(我家里的电脑,和其他两台NAS)之间无法有效保持24x7的连接。花生棒是一个可选方案,但其一个月只提供2GB的流量,感觉略坑。经过一番网络搜索,发现可以借助ngrok来实现内网与外网的联通。
什么是ngrok?
ngrok是一个ddns服务,为内网机器绑定一个公网域名之后,可以将内网机器的端口暴露在公网上,方便内网程序的调试和开发。比如,在内网机器上,想开HTTP服务的80端口,那么就可以使用ngrok,而不需要借助路由器的端口转发和端口映射功能。当然这样做的前提是,你需要一台可以从内网访问到的公网服务器,比如阿里云的云主机,或者便宜的搬瓦工VPS(一年20美金即可)。
ngrok的使用条件
- 域名 (很多域名如.top,.online域名首年都是0.88美金,具体访问namecheap.com或者namesilo.com)
- 拥有独立IP的VPS或云主机(阿里云或者搬瓦工)
ngrok服务器端编译
我使用的阿里云服务器,装的CentOS 6.5 64位系统。
安装go的编译环境
环境安装
yum -y install zlib-devel openssl-devel perl hg cpio expat-devel gettext-devel curl curl-devel perl-ExtUtils-MakeMaker hg wget gcc gcc-c++ build-essential mercurial
安装go
wget http://www.golangtc.com/static/go/1.7rc6/go1.7rc6.linux-386.tar.gz
tar -zxvf go1.7.6.linux-386.tar.gz
mv go /usr/local/
ln -s /usr/local/go/bin/* /usr/bin/
检查是否安装成功,命令 go env
如果看到下面的信息
➜ ~ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/usr/lib/golang"
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build672964581=/tmp/go-build"
CXX="g++"
CGO_ENABLED="1"
说明go环境安装成功
下面开始进行go的编译,在参考其他帖子的过程中,推荐go的编译需要git版本>=1.9,而我阿里云上的git是1.7.1因此需要升级git,我没有将步骤写在这里,因为觉得和主题不是很相关,如果你的git版本较低,可以参考这个帖子将较低版本的git升级到新版。
开始编译服务器端
声明编译的路径和必要的域名(域名改成你自己的)
#这是原版代码,编译过程会从github下载依赖包,国内网络坏境可能会有问题,下面使用的是阿里云的OSS提供的地址
#git clone https://github.com/inconshreveable/ngrok.git ~/ngrok
#推荐直接下载完整包,一次性编译无需下载
wget http://tinyoss.oss-cn-qingdao.aliyuncs.com/ngrok.zip
unzip ngrok.zip
export GOPATH=~/ngrok/ #指定GO语言所在位置
export NGROK_DOMAIN="ngrok.wuliaole.com" #这个需要改成你的域名
生成证书
cd ~/ngrok
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out rootCA.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt
生成的3个文件,分别是rootCA.pem、server.csr和server.crt,各有用处。
下面将这3个文件复制到指定位置
cp rootCA.pem assets/client/tls/ngrokroot.crt -i
cp server.crt assets/server/tls/snakeoil.crt -i
cp server.key assets/server/tls/snakeoil.key -i
不同的编译类型
如果要为不同的服务端编译,需要根据系统类型,更改go env中的变量。主要是GOOS和GOARCH这两项。
为linux-x86-64系统编译
比如我的阿里云主机,系统是CentOS 6.5 64位,就属于这种类型,分别指定变量并且执行服务器端编译:
export GOOS=linux
export GOARCH=amd64 #如果是64位系统,则修改为386
make release-server #如果是客户端,这里是make release-client
编译完成后,在路径~/ngrok/bin/linux_amd64下,会看到一个名为ngrokd的文件,这个即为服务端运行文件。
为树莓派系统编译
export GOOS=linux
export GOARCH=arm
make release-server #如果是客户端,这里是make release-client
编译完成后,在路径~/ngrok/bin/linux_arm下,会看到一个名为ngrokd的文件,这个即为服务端运行文件。
为windows系统编译服务端文件
export GOOS=windows
export GOARCH=386 #如果是64位windows,这里修改为amd64
make release-server #如果是客户端,这里是make release-client
编译完成后,在路径~/ngrok/bin/windows_386下,会看到一个名为ngrok.exe的文件,这个即为服务端运行文件。
为Mac OS编译服务端文件
export GOOS=darwin
export GOARCH=amd64 #如果是64位windows,这里修改为amd64
make release-server
编译完成后,在路径~/ngrok/bin/darwin_amd64下,会看到一个名为ngrokd的文件,这个即为服务端运行文件。
*. GOOS参数可以指定为windows、linux、freebsd、darwin (Mac OS X 10.5 or 10.6) 和nacl(Chrome 的Native Client 接口)
*. GOARCH可以指定为amd64 (64-bit x86)、386 (32-bit x86)、和arm (32-bit ARM)。
绑定域名
将编译配置时的域名ngrok.wuliaole.com,解析到服务器IP
我是DNSPOD,为wuliaole.com添加一条值为*.ngrok的A记录即可。
服务器端部署
将编译好的可执行文件移至/usr/bin/下
cp ~/ngrok/bin/ngrokd /usr/bin/
为ngrokd的运行单独开一个screen
如果你发现screen执行失败,说明你没有装,CentOS可以通过
yum install -y screen来安装screen服务,具体可以参见我的另外一个帖子《screen的安装和使用》,讲述了强大的screen的安装和使用。
screen -S ngrokd
运行ngrokd
#http
./bin/linux_amd64/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":6060" -httpsAddr=":6061" -tunnelAddr=":6062"
#https设置了tls
#./bin/linux_amd64/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":6060" -httpsAddr=":6061" -tunnelAddr=":6062" -tlsKey=./device.key -tlsCrt=./device.crt
这里详细解释一下上面这句话中参数的含义
httpAddr是访问普通的http使用的端口号,用后面用 `ngrok.wuliaole.com:6060 来访问服务httpsAddr是访问的https使用的端口号,同上,只不过是需要https的服务访问才用这个端口tunnelAddr是通道的端口号,这个端口是Ngrok用来通信的,所以这个端口在服务器上和客户端上设置必须要对应才可以正常的链接,默认不填写好像是4433。
防火墙呢
ngrok客户端编译
Windows客户端
好了,你现在服务器上,已经有一个ngrokd服务在运行了,那么客户端与服务器端如何连接呢?
也没啥难的,就是继续修改go环境的编译参数,继续编译客户端就好了
GOOS=windows
GOARCH=amd64
make release-client
我是在64位的windows 10环境下连接服务器,其他参数,大家可以参考服务端程序的参数,自行进行相应的修改。
编译完成后,在路径~/ngrok/bin/windows_amd64下,会看到一个名为ngrok.exe的文件,这个即为服务端运行文件。使用scp命令或通过ftp,将其下载到你的本地电脑上即可。
然后,创建一个ngrok.cfg文件来保存配置,内容很简单
server_addr: "ngrok.wuliaole.com:6062"
trust_host_root_certs: false
然后,记得要采用cmd命令的方式来运行客户端程序,一句话
./ngrok -subdomain resiliosync -proto=http -config=ngrok.cfg 8000
上面的8000是你想暴露的http服务端口号。如果还想暴露更多诸如ssh或者其他更多服务的端口,自行添加即可。
树莓派或者linux客户端
在ngrokd文件的同一级目录下,vim或者touch创建ngrok.cfg文件(yml语言格式)
这里假设你想用ssh端口管理树莓派或者你的linux服务器,ssh的默认端口是22,但是你想让这台树莓派将外网的10086端口转发到内网的22,那么设置如下:
server_addr: ngrok.wuliaole.com:6062
trust_host_root_certs: false
tunnels:
http:
proto:
http: 80 #这里是你想暴露的http服务端口号
subdomain: pi #这里给你想暴露的http服务起个名字
ssh:
remote_port: 10086
proto:
tcp: 22
这里我把需要转发的http和ssh都写入配置文件,其他tcp服务语法格式和ssh相似,remote_port为远程端口,等下外网连接的时候用的就是这个remote_port的端口号。tcp:22为需要转发的本地端口。
在树莓派上运行
./ngrok-for-arm -config=ngrok.cfg start http ssh
这时候,处于内网的树莓派就可以通过连接你的服务器(运行ngrokd的外网服务器)来提供80、22、10086等端口的服务了。
比如,你的外网机器,就可以使用ssh来连接和管理处于内网环境的树莓派了。
ssh -p 10086 pi@ngrok.wuliaole.com
结语
ngrok确实是非常强大,没啥想说的了。