目录
1、简介 1
2、 必要条件 2
2.1、ngrok服务器 2
2.2、域名 2
2.3、ngrok客户端 2
3、 安装依赖包 2
4、 安装golang 2
5、 下载ngrok源码 3
6、 生成自签名证书 3
7、 替换证书 4
8、 编译 4
9、 启动服务端 5
10、 编译客户端 5
11、 设置本地客户端 6
12、 启动客户端 6
13、 客户端tomcat服务 6
14、 使用域名访问 7
15、 window的端口转发 7
16、测试转发 9
17、转发ssh 10
18、 ngrok配合端口转发 11
内网穿透想必很多做过开发的同志都很了解,大部分人选择网上寻找各种现成的,比如ngrok官网、ittun-ngrok、sunny-ngrok或者花生壳之类的。但是世界上没有免费的午餐,要不就是收费,要不就是免费但是偶尔会出现连接失败的问题(当然大多数时间是没有问题的)。如果想访问内网上的某台机器提供的某个服务,而这个内网机器又没有公网ip的情况下,就可以使用这个办法解决。思路就是找一台在公网的的服务器,比如阿里云、腾讯云主机,在该主机上安装ngrok服务端,然后在内网的那台机器上安装对应的ngrok客户端。当然前台是内网的这台机器可以访问公网。然后通过客户端和服务端建立一个隧道,让访问服务端指定域名和端口的流量通过服务端转发到客户端实现访问内网的服务。
需要有公网ip,可以提供公网服务。我本次测试的服务器是腾讯云服务器,操作系统CentOS7.6。
域名就是访问公网解析的域名,需要解析到上面ngrok的服务器对应的公网ip上。
内网提供服务的机器,他没有公网ip,但是能访问公网。
腾讯机器操作系统安装好了,他自带了会有腾讯yum源,可以直接使用yum进行包的安装。当然,你也可以做个本地yum源。
#yum install mercurial git #yum install gcc gcc-c++ make #yum install \ autoconf automake binutils \ bison flex gcc gcc-c++ gettext \ libtool make patch pkgconfig \ redhat-rpm-config rpm-build rpm-sign \ ctags elfutils indent patchutils |
# rpm --import https://mirror.go-repo.io/centos/RPM-GPG-KEY-GO-REPO # curl -s https://mirror.go-repo.io/centos/go-repo.repo | tee /etc/yum.repos.d/go-repo.repo # yum -y install golang |
Golang,Go语言支持,因为Ngrok是基于Go语言编写的
Git是下载ngrok源码用的。
# git clone https://github.com/tutumcloud/ngrok.git ngrok |
下载后会在当前目录产生一个ngrok文件夹,里面结构如下:
# ls ngrok # ls assets base.pem bin CONTRIBUTORS LICENSE README.md server.csr src base.key base.srl contrib docs Makefile server.crt server.key |
使用ngrok.com官方服务时,我们使用的是官方的SSL证书。自建ngrokd服务,如果不想买SSL证书,我们需要生成自己的自签名证书,并编译一个携带该证书的ngrok客户端。
证书生成过程需要一个NGROK_BASE_DOMAIN。 以ngrok官方随机生成的地址xxx.ngrok.com为例,其NGROK_BASE_DOMAIN就是“ngrok.com”,如果你要提供服务的地址为“www.redesktop.kadwf123.com”,那NGROK_BASE_DOMAIN就应该 是“redesktop.kadwf123.com”。这里需要注意,这两个域名均需要有对应的主机A记录,能够从客户端ping通。我此次测试的客户端,就是我本地的笔记本电脑。
从我的笔记本ping这两个地址要都能通。
阿里云域名解析如下:
下面就是生成证书的命令
# cd ngrok # NGROK_DOMAIN="redesktop.kadwf123.com" # openssl genrsa -out base.key 2048 # openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.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 base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt |
# cp base.pem assets/client/tls/ngrokroot.crt # cp base.pem assets/client/tls/snakeoilca.crt # cp server.crt assets/server/tls/snakeoil.crt # cp server.key assets/server/tls/snakeoil.key |
# make release-server release-client |
编译成功后会在bin目录下找到ngrokd和ngrok这两个文件。其中ngrokd 就是服务端程序了。
# cd bin # ll total 25604 -rwxr-xr-x 1 root root 2924358 Aug 1 01:08 go-bindata -rwxr-xr-x 1 root root 12942032 Aug 1 03:12 ngrok -rwxr-xr-x 1 root root 10345240 Aug 1 03:12 ngrokd |
# ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="redesktop.kadwf123.com" -httpAddr=":80" -httpsAddr=":443" |
httpAddr、httpsAddr 分别是 ngrok 用来转发 http、https 服务的端口,可以随意指定。ngrokd 还会开一个 4443 端口用来跟客户端通讯(可通过 -tunnelAddr=”:xxx” 指定)。这个就表示,客户端的机器,提供http服务,就通过80端口转发,如果提供https服务,就从443端口转发。端口可以自定。
Windows:
# GOOS=windows GOARCH=amd64 make release-client |
下面是不同系统生成不同客户端的版本 替换GOODS 和GOARCH的值即可。
#Linux 平台 32 位系统:GOOS=linux GOARCH=386 #Linux 平台 64 位系统:GOOS=linux GOARCH=amd64 #Windows 平台 32 位系统:GOOS=windows GOARCH=386 #Windows 平台 64 位系统:GOOS=windows GOARCH=amd64 #MAC 平台 32 位系统:GOOS=darwin GOARCH=386 #MAC 平台 64 位系统:GOOS=darwin GOARCH=amd64 #ARM 平台:GOOS=linux GOARCH=arm |
执行对应的命令会在bin目录下生成相对应的windows目录,ngrok.exe就存放在对应目录下。将对应的ngrok.exe下载到本地(此处就是我的笔记本)。
# ll total 25604 -rwxr-xr-x 1 root root 2924358 Aug 1 01:08 go-bindata -rwxr-xr-x 1 root root 12942032 Aug 1 03:12 ngrok -rwxr-xr-x 1 root root 10345240 Aug 1 03:12 ngrokd drwxr-xr-x 2 root root 4096 Aug 1 03:14 windows_amd64 # cd windows_amd64/ # ll total 12340 -rwxr-xr-x 1 root root 12634624 Aug 1 03:14 ngrok.exe |
我将ngrok.exe文件下在我本地D:\Users\ngrok下面:
在该目录下新增ngrok.cfg文件,内容如下:
server_addr: "redesktop.kadwf123.com:4443" trust_host_root_certs: false |
同级目录下新建一个启动脚本startup.bat,内容如下:
@echo on cd %cd% #ngrok -proto=tcp 22 #ngrok start web ngrok -config=ngrok.cfg -log=ngrok.log -subdomain=www 8080 |
其中,-config指向配置文件,-log存放日志文件位置,-subdomain为自定义的域名前缀。8080为端口号。
启动,点击启动脚本startup.bat完成启动。
展示如下,表示正常。
此时我的客户端运行了tomcat服务,对外提供8080端口。
我们如果通过域名访问,也能打开这个tomcat的欢迎页面,就表示测试成功了。
其实访问成功了,只不过我这个域名没有备案,现在已经无法访问了。
上面已经实现了从公网直接访问域名可以直接访问到我这台笔记本的某个端口,如果我的笔记本这个端口提供了某项服务,那么直接通过域名就可以访问到这项服务。如果在配合使用我这台笔记本做端口转发,就可以在转发到局域网中的另一台不在公网环境的机器上。拓扑图如下:
考察上面这幅图中,Ngrok Server A就是腾讯云服务器(也可以是阿里云、华为云,看自己情况),公网用户就是随意一个能访问公网的用户,需要访问企业内网服务器D,但是又不能直接访问企业内网服务器D的人。Ngrok client C就是位于企业内部的一台可以访问公网,并且跟企业内网服务器D在同一局域网的服务器,这里我就假设是我的笔记本。企业内网服务器D,就是最终提供服务的机器,也是终端用户B需要最终访问的机器,这里简单起见,我就在笔记上弄个了一台centos7的虚机。
角色 |
ip |
域名 |
Ngrok Server A |
公网ip,略 |
略 |
公网用户B |
我的笔记本192.168.100.16 |
无 |
Ngrok Client C |
我的笔记本192.168.100.16 |
无 |
企业内网服务器D |
笔记本上的虚机192.168.100.21 |
无 |
这里公网用户B和ngrok client C就用一台机器模拟,其实效果一样。
在ngrok client C上做端口转发如下:
netsh interface portproxy add v4tov4 listenaddress=192.168.100.16 listenport=62002 connectaddress=192.168.100.21 connectport=80 |
要用管理员身份启动cmd,否则添加不成功。可以使用如下命令检查添加的端口转发条目:
netsh interface portproxy show v4tov4 |
如果添加错了可以使用如下命令删除:
netsh interface portproxy delete v4tov4 listenaddress=192.168.100.16 listenport=62002 |
解释一下这其中的参数意义
1.listenaddress -- 本地ip地址,此处就是ngrok客户端
2.listenport -- 本地监听的端口,此处就是ngrok客户端的某个端口,该端口可以随意定,只要当前未使用就行
3.connectaddress -- 需要转发到的远程地址,这里就是笔记本虚机的地址(企业内网服务器D)
4.connectport -- 需要转发到的远程机器的服务端口,这里就是笔记本虚机的某个服务端口,比如虚机上跑的有httpd,端口80,那就是80端口
上例中,我们通过笔记本上的62002端口向虚机上的http服务的80端口做了转发,那么当我们访问笔记本的62002的时候,应该是访问的是虚机上的http服务,如下:
可以看到转发成功了。
上例是转发到http的80端口,当然,也可以转发到任意其他服务端口,比如我们在测个转发到ssh的。
添加端口转发策略:
netsh interface portproxy add v4tov4 listenaddress=192.168.100.16 listenport=62003 connectaddress=192.168.100.21 connectport=22 |
查看添加:
netsh interface portproxy show v4tov4 |
通过crt测试ssh连接:
可以看到连接成功。
所以将ngrok和端口转发配合使用就能访问不在公网的中的企业内网的环境,在实际工作中,临时性的需要访问企业内网的情况很多,使用这种方式不失为一种很好的办法。由于我这个域名没有备案,目前无法访问了,所以这里这个完整的测试效果我这边演示不出来。