本地调试,搭建属于自己的ngro_k服务器
本文仅记录学习,转载请注明出处~
ngrok 是一个反向代理的开源软件,至于为什么要使用ngrok,百度百科这样说:
最近在学微信公众号开发,开发过程需要与微信的服务端交互,直接拿自己的电脑当然是不行的,因为我们的电脑连接的是局域网,网址非固定,且跟公网连接不上。如百度上的解释,若是每次测试都得把代码写完然后打包放到服务器上去,太折腾了。最简便的方法莫过于就在本机进行开发和测试。那么要如何打通本地与外网的通道,使微信服务器能找到我的本地主机呢?办法还是有的,借用内网穿透工具可以实现。在市面上内网穿透工有很多。但无一例外,使用免费内网穿透服务是不稳定的,想要长久稳定使用就得花钱充vip,vip之间还分等级......考虑到后面开发需要很长一段时间,最后我决定把闲置已久的主机和域名用来搭一个ngrok服务器。
更多内网穿透工具(可以尝试下免费的):可以实现内网穿透的几款工具,内网穿透的实现和原理解析
1、先了解几个概念:
正向代理 (Forward Proxy)与反向代理(reverse proxy)
正向代理,proxy(代理) 和 client(用户) 同属一个 LAN(局域网),对 server 透明;Lhost 为了访问到 Rhost,向 proxy 发送了一个请求并且指定目标是 Rhost,然后 proxy 向 Rhost 转交请求并将获得的内容返回给 Lhost,简单来说正向代理就是 proxy 代替了我们去访问 Rhost。 vpn的应用是正向代理的一种。
反向代理,proxy 和 server 同属一个 LAN,对 client 透明。Lhost 只向 proxy 发送普通的请求,具体让他转到哪里,proxy 自己判断,然后将返回的数据递交回来,这样的好处就是在某些防火墙只允许 proxy 数据进出的时候可以有效的进行穿透。
实际上 proxy 在两种代理中做的事都是代为收发请求和响应,不过从结构上来看正好左右互换了下,所以把前者那种代理方式叫做正向代理,后者叫做反向代理。
端口映射:
端口映射:端口映射就是将内网中的主机的一个端口映射到外网主机的一个端口,提供相应的服务。当用户访问外网IP的这个端口时,服务器自动将请求映射到对应局域网内部的机器上。比如,我们在内网中有一台Web服务器,但是外网中的用户是没有办法直接访问该服务器的。于是我们可以在路由器上设置一个端口映射,只要外网用户访问路由器ip的80端口,那么路由器会把自动把流量转到内网Web服务器的80端口上。并且,在路由器上还存在一个Session,当内网服务器返回数据给路由器时,路由器能准确的将消息发送给外网请求用户的主机。在这过程中,路由器充当了一个反向代理的作用,他保护了内网中主机的安全
端口转发:
端口转发(Port forwarding),有时被叫做隧道,是安全壳(SSH) 为网络安全通信使用的一种方法。比如,我们现在在内网中,是没有办法直接访问外网的。但是我们可以通过路由器的NAT方式访问外网。假如我们内网现在有100台主机,那么我们现在都是通过路由器的这一个公网IP和外网通信的。那么,当互联网上的消息发送回来时,路由器是怎么知道这个消息是给他的,而另外消息是给你的呢?这就要我们的ip地址和路由器的端口进行绑定了,这时,在路由器中就会有一个内网ip和路由器端口对应的一张表。当路由器的10000端口收到消息时,就知道把消息发送给他,而当20000端口收到消息时,就知道把消息发送给你。这就是端口转发,其转发一个端口收到的流量,给另一个主机:
进一步理解隧道:SSH隧道与端口转发及内网穿透
小结:我们搭建ngrok服务器后,实现了隧道(端口转发)技术,使ngrok服务器能够反向代理我们本地主机。当有外网(如微信后台)直接发送请求给 服务器的域名+某个端口 , 服务器会把请求原封不动的转发给 本地主机+指定端口的位置。在整个过程中,ngrok服务器仅仅充当了一个对外接收请求的门面,实际上请求还是会被转发到本地主机处理,这就是隧道打通之后,代理的大致过程。
1、前期准备:
- 一台有固定ip的服务器
- 一个域名,用来生成访问域名
- 一个本地电脑
域名须先备案!!!我这里用的是阿里云服务器。大陆的服务器想要通过域名访问,光是实名认证是没用的,服务器域名都得备案。
域名解析(以阿里云产品为例):
在控制台找自己购买的域名,进入域名服务,在域名列表,找到你所要用到的那个域名点进去解析
因在本地多仅用于测试,舍不得用顶级域名,就用二级域名。如图第1步,添加一个二级域名如:ngrok.xiongmm.cn到你的服务器上(A记录), 再添加一个*.ngrok的泛解析(还是A记录), 解析的地址都是你的服务器地址。(泛解析一定要加上,这意味着后面部署好后,形如xxx.ngrok.xiongmm.cn的域名都可访问,这个xxx为任意的)。顶级域名解析同理,除步骤2的两个记录之外还应再加一个泛解析。
2、安装ngrok需要的环境:
1、安装golang,ngrok是go语言写的,需要go语言的环境支持,golang是go语言在官网的名字。
选择源码安装最好,因为我用yum安装后面出错,可能yum源下的版本会出问题:
下载源码:(root用户下的操作)
cd /usr/src
wget https://studygolang.com/dl/golang/go1.12.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.12.linux-amd64.tar.gz #解压到/usr/local目录
配置环境变量:
vi /etc/profile
在最后一行加入以下内容,并保存退出:
#go
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=/root/go
export PATH=$PATH:$GOPATH/BIN
执行命令立即生效:
source /etc/profile
查看安装情况
go version
输出内容就证明安装成功。
2、安装git,git安装是为了从github获取ngrok源代码,当然也可以自己从github下载然后再传到服务器。
选择源码安装,依然不推荐yum安装,yum源的版本太低,就算勉强能用很快就要换的:
不同版本自选:镜像
## 查看自带的版本git version 1.8.3.1
git --version
## 移除原来的版本
yum remove git
#安装所需软件包
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
yum install gcc-c++ perl-ExtUtils-MakeMaker
#切换到src目录下载源码
cd /usr/src
wget https://www.kernel.org/pub/software/scm/git/git-2.7.3.tar.gz
#解压
tar xzf git-2.7.3.tar.gz
#编译,安装
cd git-2.7.3
make prefix=/usr/local/git all
make prefix=/usr/local/git install
#加入环境变量
echo "export PATH=$PATH:/usr/local/git/bin" >> /etc/profile
source /etc/profile
#查看安装结果
git --version
3、安装ngrok并配置服务器
下载源码:(非官方源码,修复部分问题,亲测可用)
cd /usr/local
git clone https://github.com/tutumcloud/ngrok.git ngrok
为域名生成自签名证书(没有证书,不可使用https协议):
(记得改成自己的域名)
cd ngrok
NGROK_DOMAIN="ngrok.xiongmm.cn" #改成自己要用的二级域名或者顶级域名
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
替换掉原本ngrok.com的证书,会提示overwrite,输入y回车即可
cp base.pem assets/client/tls/ngrokroot.crt
编译服务端:
make release-server release-client
编译成功后会在bin目录下找到ngrokd和ngrok这两个文件。其中ngrokd 就是服务端程序了。
编译客户端:golang交叉编译,需根据客户端的计算机位数,以及操作系统自行选择。
<!--linux服务端-->
GOOS=linux GOARCH=386 make release-server (32位)
GOOS=linux GOARCH=amd64 make release-server(64位)
<!--Mac OS客户端-->
GOOS=darwin GOARCH=386 make release-client
GOOS=darwin GOARCH=amd64 make release-client
<!--windows客户端-->
GOOS=windows GOARCH=386 make release-client
GOOS=windows GOARCH=amd64 make release-client
本地为win10 系统 64位,故执行最后一条:
cd /usr/local/ngrok
GOOS=windows GOARCH=amd64 make release-client
在bin目录下会生成相对应的可执行文件ngrok.exe:
启动服务端:domain需要改成你自己的域名
cd /usr/local/ngrok
./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain=ngrok.xiongmm.cn -httpAddr=:80 -httpsAddr=:443
在代理服务器中,http协议是使用80端口,https使用443端口,可以任意指定,但是微信开发填服务器地址不能出现端口,因此使用协议默认端口号。另外ngrok还会开一个4443端口与服务端通讯,客户端配置文件会用到。
配置客户端:
配置:将ngrok.exe文件下载到本地,然后在本地同级目录下创建配置文件ngrok.cfg 以及启动文件startup.bat
编写ngrok.cfg文件:
server_addr: "ngrok.xiongmm.cn:4443"
trust_host_root_certs: false
tunnels:
http:
subdomain: "anyname"
proto:
http: "8080"
https:
subdomain: "anyname"
proto:
https: "8080"
参数解析:
- server_addr,服务端与本地通讯地址,服务端ngrok为此开启的端口是4443,端口貌似不可以改
- trust_host_root_certs:填写false,反正填true会连不上
- tunnels:隧道
- subdomain:子域名,域名最前面那部分,因为添加了泛解析,故可以填任意的,不指定的话会随机生成
- proto:代理
- http: "8080":这里的http 8080是指本地的http协议端口,可以填任意值
编写startup.bat文件:
@echo on
#ngrok start web
ngrok.exe -config ngrok.cfg -log=ngrok.log start http https
参数解析:
- -config ngrok.cfg 配置文件为ngrok.cfg,运行ngrok.exe时会到配置文件读取相应信息
- -log=ngrok.log 日志文件,会自动生成
- start http https 运行exe文件后开启本地http 和 https服务的映射
启动客户服务:
点击startup.bat运行,出现状态为绿色即为本地主机与服务器的隧道打通了。
测试一下用域名是否可以连外网,写个servlet,在tomcat里面运行测试一下:
内网穿透成功!
4、错误总结
如果过程中出错,看是否为如下问题:
1、在编译过程中有可能出现如下错误:
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
-debug=false \
-o=src/ngrok/client/assets/assets_release.go \
assets/client/...
make: bin/go-bindata: Command not found
make: *** [client-assets] Error 127
解决方法:前往go安装目录的bin目录下找到go-bindata,将他移动到ngrok/bin下 (没有bin,可新建一个) ,其实这个问题在我用源码的方式重装golang之后就没出现了。
2、碰到这种连不上的错误
出问题的可能性有很多,解决方法只能是逐个排除:
第一,先保证检查的是自己服务端是否开启服务。
第二,检查阿里云域名解析是否正确,比如我要用顶级域名abc.com,然后你除了用@方式解析顶级域名abc.com之外,是否有使用泛解析: *.abc.com,解析地址要指向自己的服务器IP。二级域名解析在前面有说,往上翻。
第三,查看阿里云服务器安全组是否设置:找到自己的服务器实例→管理→本实例安全组→安全组列表→配置规则→添加安全组规则(阿里云安全组添加示例),添加http 80和 https 443以及全部ICP+UDP这三个分组。安全组的概念是在阿里云服务器才有的,设置这道关卡对初学者来说简直鸡肋。
第四,设置防火墙,在安全组开放端口之后,另外还要在防火墙开放端口,不然外面访问不了你的服务器,这里就先把防火墙关掉吧,省事一些,后面继续优化。
systemctl stop firewalld.service
第五,端口被占用,当前服务器有其他web应用占用了80端口,解决方法就是直接把进程杀死:
查询: netstat -lnp |grep 端口号
kill 进程号
排除上面五个问题,服务器主机本身应该没问题了。再重启bat文件运行本地服务。如果还是失败,继续排查
第六,检查本地配置文件是否填写正确,
如果配置文件所在位置以及配置问价内容都没错,那么排除本地客户端错误的可能性。
这个时候还有错,就推翻重来吧,很大可能是你在生成证书或者启动服务端的时候域名没有正确填写自己的。重来只需把整个ngrok文件删了,从get clone 拉去ngrok源码那一步开始。
2、若是遇到如下这种错(隧道不可用),说明你都成功了,只是用错了端口,比如http协议映射的本地端口为8080,而你的本地web服务器tomcat开启的却是80端口,本地http80端口没有打通隧道当然不可用。
解决办法:在ngrok.cfg文件把http端口改为80,再重启.bat文件。亦或者把tomcat的使用端口改回8080。
对于需要更换域名,或者推倒重来,都应先把ngrok文件整个删掉,然后从git clone下载源码那一步重复开始。
5、优化服务
后台自动运行:在ngrok目录下执行以下命令会启动服务端:
./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain=ngrok.xiongmm.cn -httpAddr=:80 -httpsAddr=:443
但是若是关闭了bash,服务也会关闭,要让他方便的在后台默默运行,得把它打包成一个服务。
输入命令:
vim /etc/systemd/system/ngrok.service
添加如下内容:(域名domain要换成自己的域名!!)
[Unitt]
Description=ngrok
After=network.target
[Service]
#不需要双引号,
ExecStart=/usr/local/ngrok/bin/ngrokd -tlsKey=/usr/local/ngrok/server.key -tlsCrt=/usr/local/ngrok/server.crt -domain=ngrok.xiongmm.cn -httpAddr=:80 -httpsAddr=:443
#设置自动重启,若服务被系统关闭,可自启动,手动kill可关闭
Restart=always
RestartSec=5
StartLimitInterval=0
RestartPreventExitStatus=SIGKILL
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
再执行以下命令
systemctl start ngrok.service
现在可以把服务器bash关掉,然后在本地自由的使用。
想停止服务端服务的话,查找并杀掉此进程即可:
netstat -lnp|grep 80 #找到80端口进程的PID
kill PID
防火墙开启端口:
防火墙没开的端口,外面想要访问是不可以的,但是之前这样直接把防火墙关了是不是不太好?想了想还是开着防火墙稳重一些,用以下命令把三个要用到的端口(80,443,4443)开启::
firewall-cmd --state #查看防火墙状态
systemctl start firewalld.service #开启防火墙
firewall-cmd --zone=public --add-port=80/tcp --permanent #永久 开放80端口
firewall-cmd --reload # 配置立即生效
firewall-cmd --zone=public --query-port=80/tcp #查看80端口是否开放,返回yes则开放成功
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --query-port=443/tcp #查看443端口是否开放,返回yes则开放成功
firewall-cmd --zone=public --add-port=4443/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --query-port=4443/tcp #查看4443端口是否开放,返回yes则开放成功
弄好之后,在本地与外网交互就很方便了。其实步骤也没几个,但是需要注意的地方比较多。
下面再说一下做微信公众号开发的一个大坑!!!!
在微信公众号的服务器配置当中,使用这个域名报参数错误。
然而我在浏览器上就能访问这个网址返回相应信息,也就是说地址是可以被外网访问。
同样,我尝试了一下用之前免费的ngrok服务提供的域名,配置成功?:
启动服务:
配置成功
我一脸茫然????,是我的域名有毒吗??为此我试过了好多次,我把本地的映射域名也改成了80端口依旧无效,甚至我怀疑域名太长了,于是我就重新部署了一下换成了顶级域名:
可以被外网访问:
但就是不行,该你参数错误还得错:
网上有人说,域名被微信屏蔽了,就把链接发我微信上,点开试了下,好像确实是如此:
咋办,辛苦一场,如果真的是微信屏蔽了,先申请恢复,等几天再试一下。
还别说,微信处理的效率还挺高,确认我是一个遵纪守法的好公民后,当天下午就把我域名从小黑单里拉出来了。问题果然是出在这里!
之后就可以随便使用了。
有什么问题可以提出来,欢迎一起交流。
参考文档:
https://ubock.com/article/31-4
https://www.jianshu.com/p/f5c2a55e77bd
https://blog.csdn.net/yjc_1111/article/details/79353718
https://blog.csdn.net/weixin_41941052/article/details/98949052