老叔教你亲手搭建一个Ngrok内网穿透服务器
最近公司需要开发公众号,在调试的时候就是个老大难问题,一般是需要内网穿透方式来让外网能够访问到本地的程序,提高我们的开发调试效率,一般大家会才用natapp
、向日葵、ngrok
等,这些都做得不错,但是你要用得好、用得舒心,还是得花钱,刚好我之前花了三百多块钱买了3年的云主机,所以就想着要不自己折腾一个ngrok吧,所以就有这个这篇文章
认识ngrok
这次我们需要用到ngrok
这个东东,那么首先需要基本了解一下它是个啥?能干啥?ngrok
是一款用Golang
语言打造的开源的内网穿透软件,它可以帮助我们把内网的应用提供给外网用户访问。ngrok的开源地址是https://github.com/inconshreveable/ngrok
搭建ngrok服务器
在搭建之前,我们需要准备两个东西:
- 外网服务器
- 域名
如果这两个没有的话,那就不好搞咯。这里我们先在服务器上安装好Golang
的编译环境,由于我这边被墙了,所以就只有访问https://studygolang.com/dl来下载了。在1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@VM_175_142_centos golang]# wget https://studygolang.com/dl/golang/go1.14.2.linux-amd64.tar.gz
--2020-04-23 12:57:26-- https://studygolang.com/dl/golang/go1.14.2.linux-amd64.tar.gz
Resolving studygolang.com (studygolang.com)... 59.110.219.94
Connecting to studygolang.com (studygolang.com)|59.110.219.94|:443... connected.
HTTP request sent, awaiting response... 303 See Other
Location: https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz [following]
--2020-04-23 12:57:27-- https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
Resolving dl.google.com (dl.google.com)... 203.208.41.33, 203.208.41.41, 203.208.41.38, ...
Connecting to dl.google.com (dl.google.com)|203.208.41.33|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 123658438 (118M) [application/octet-stream]
Saving to: ‘go1.14.2.linux-amd64.tar.gz’
100%[====================================================================================================================================================================>] 123,658,438 9.72MB/s in 13s
2020-04-23 12:57:41 (9.04 MB/s) - ‘go1.14.2.linux-amd64.tar.gz’ saved [123658438/123658438]go1.14.2.linux-amd64.tar.gz
文件解压后会得到一个go
文件,那么现在我们需要修改环境变量/etc/profile
或者$HOME/.profile
:再1
2export GOROOT=你的解压目录/go
export PATH=$PATH:$GOROOT/binsource /etc/profile
让配置文件即刻生效,这时候就可以看到我们的go命令是可执行的现在,我们继续去1
2
3[root@VM_175_142_centos go]# go version
go version go1.14.2 linux/amd64github
上下载ngrok
源码把1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17[root@VM_175_142_centos ngrok]# wget https://github.com/inconshreveable/ngrok/archive/master.zip
--2020-04-23 13:09:37-- https://github.com/inconshreveable/ngrok/archive/master.zip
Resolving github.com (github.com)... 13.250.177.223
Connecting to github.com (github.com)|13.250.177.223|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://codeload.github.com/inconshreveable/ngrok/zip/master [following]
--2020-04-23 13:09:38-- https://codeload.github.com/inconshreveable/ngrok/zip/master
Resolving codeload.github.com (codeload.github.com)... 54.251.140.56
Connecting to codeload.github.com (codeload.github.com)|54.251.140.56|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 200090 (195K) [application/zip]
Saving to: ‘master.zip’
100%[====================================================================================================================================================================>] 200,090 673KB/s in 0.3s
2020-04-23 13:09:39 (673 KB/s) - ‘master.zip’ saved [200090/200090]master.zip
解压出来进入到1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106[root@VM_175_142_centos ngrok]# unzip master.zip
Archive: master.zip
a8e7fa486348f391f4bdf241344d798297f953bc
creating: ngrok-master/
inflating: ngrok-master/.gitignore
inflating: ngrok-master/.travis.yml
inflating: ngrok-master/CONTRIBUTORS
inflating: ngrok-master/LICENSE
inflating: ngrok-master/Makefile
inflating: ngrok-master/README.md
creating: ngrok-master/assets/
creating: ngrok-master/assets/client/
inflating: ngrok-master/assets/client/page.html
creating: ngrok-master/assets/client/static/
creating: ngrok-master/assets/client/static/css/
inflating: ngrok-master/assets/client/static/css/bootstrap.min.css
inflating: ngrok-master/assets/client/static/css/highlight.min.css
creating: ngrok-master/assets/client/static/img/
inflating: ngrok-master/assets/client/static/img/glyphicons-halflings.png
creating: ngrok-master/assets/client/static/js/
inflating: ngrok-master/assets/client/static/js/angular-sanitize.min.js
inflating: ngrok-master/assets/client/static/js/angular.js
inflating: ngrok-master/assets/client/static/js/base64.js
inflating: ngrok-master/assets/client/static/js/highlight.min.js
inflating: ngrok-master/assets/client/static/js/jquery-1.9.1.min.js
inflating: ngrok-master/assets/client/static/js/jquery.timeago.js
inflating: ngrok-master/assets/client/static/js/ngrok.js
inflating: ngrok-master/assets/client/static/js/vkbeautify.js
creating: ngrok-master/assets/client/tls/
inflating: ngrok-master/assets/client/tls/ngrokroot.crt
inflating: ngrok-master/assets/client/tls/snakeoilca.crt
creating: ngrok-master/assets/server/
creating: ngrok-master/assets/server/tls/
inflating: ngrok-master/assets/server/tls/snakeoil.crt
inflating: ngrok-master/assets/server/tls/snakeoil.key
creating: ngrok-master/contrib/
inflating: ngrok-master/contrib/com.ngrok.client.plist
creating: ngrok-master/docs/
inflating: ngrok-master/docs/CHANGELOG.md
inflating: ngrok-master/docs/DEVELOPMENT.md
inflating: ngrok-master/docs/SELFHOSTING.md
creating: ngrok-master/src/
creating: ngrok-master/src/ngrok/
creating: ngrok-master/src/ngrok/cache/
inflating: ngrok-master/src/ngrok/cache/lru.go
creating: ngrok-master/src/ngrok/client/
inflating: ngrok-master/src/ngrok/client/cli.go
inflating: ngrok-master/src/ngrok/client/config.go
inflating: ngrok-master/src/ngrok/client/controller.go
inflating: ngrok-master/src/ngrok/client/debug.go
inflating: ngrok-master/src/ngrok/client/main.go
inflating: ngrok-master/src/ngrok/client/metrics.go
inflating: ngrok-master/src/ngrok/client/model.go
creating: ngrok-master/src/ngrok/client/mvc/
inflating: ngrok-master/src/ngrok/client/mvc/controller.go
inflating: ngrok-master/src/ngrok/client/mvc/model.go
inflating: ngrok-master/src/ngrok/client/mvc/state.go
extracting: ngrok-master/src/ngrok/client/mvc/view.go
inflating: ngrok-master/src/ngrok/client/release.go
inflating: ngrok-master/src/ngrok/client/tls.go
inflating: ngrok-master/src/ngrok/client/update_debug.go
inflating: ngrok-master/src/ngrok/client/update_release.go
creating: ngrok-master/src/ngrok/client/views/
creating: ngrok-master/src/ngrok/client/views/term/
inflating: ngrok-master/src/ngrok/client/views/term/area.go
inflating: ngrok-master/src/ngrok/client/views/term/http.go
inflating: ngrok-master/src/ngrok/client/views/term/view.go
creating: ngrok-master/src/ngrok/client/views/web/
inflating: ngrok-master/src/ngrok/client/views/web/http.go
inflating: ngrok-master/src/ngrok/client/views/web/view.go
creating: ngrok-master/src/ngrok/conn/
inflating: ngrok-master/src/ngrok/conn/conn.go
inflating: ngrok-master/src/ngrok/conn/tee.go
creating: ngrok-master/src/ngrok/log/
inflating: ngrok-master/src/ngrok/log/logger.go
creating: ngrok-master/src/ngrok/main/
creating: ngrok-master/src/ngrok/main/ngrok/
inflating: ngrok-master/src/ngrok/main/ngrok/ngrok.go
creating: ngrok-master/src/ngrok/main/ngrokd/
inflating: ngrok-master/src/ngrok/main/ngrokd/ngrokd.go
creating: ngrok-master/src/ngrok/msg/
inflating: ngrok-master/src/ngrok/msg/conn.go
inflating: ngrok-master/src/ngrok/msg/msg.go
inflating: ngrok-master/src/ngrok/msg/pack.go
creating: ngrok-master/src/ngrok/proto/
inflating: ngrok-master/src/ngrok/proto/http.go
inflating: ngrok-master/src/ngrok/proto/interface.go
inflating: ngrok-master/src/ngrok/proto/tcp.go
creating: ngrok-master/src/ngrok/server/
inflating: ngrok-master/src/ngrok/server/cli.go
inflating: ngrok-master/src/ngrok/server/control.go
inflating: ngrok-master/src/ngrok/server/http.go
inflating: ngrok-master/src/ngrok/server/main.go
inflating: ngrok-master/src/ngrok/server/metrics.go
inflating: ngrok-master/src/ngrok/server/registry.go
inflating: ngrok-master/src/ngrok/server/tls.go
inflating: ngrok-master/src/ngrok/server/tunnel.go
creating: ngrok-master/src/ngrok/util/
inflating: ngrok-master/src/ngrok/util/broadcast.go
inflating: ngrok-master/src/ngrok/util/errors.go
inflating: ngrok-master/src/ngrok/util/id.go
inflating: ngrok-master/src/ngrok/util/ring.go
inflating: ngrok-master/src/ngrok/util/shutdown.go
creating: ngrok-master/src/ngrok/version/
inflating: ngrok-master/src/ngrok/version/version.gongrok
源码解压目录,并创建一个ssl
目录,用于存放自定义证书执行完上面的命令后,会得到这些文件:1
2
3
4
5
6
7
8mkdir ssl&& cd ssl
export NGROK_DOMAIN="ngrok.52fx.biz"
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 8888 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 8888我们现在把这个文件复制到ngrok对应的目录并覆盖原文件1
2
3
4
5
6
7
8
9[root@VM_175_142_centos ssl]# tree
.
|-- device.crt
|-- device.csr
|-- device.key
|-- rootCA.key
|-- rootCA.pem
`-- rootCA.srl现在我们就来开始编译1
2
3
4
5
6
7[root@VM_175_142_centos ssl]# cp rootCA.pem ../assets/client/tls/ngrokroot.crt
cp: overwrite ‘../assets/client/tls/ngrokroot.crt’? y
[root@VM_175_142_centos ssl]# cp device.crt ../assets/server/tls/snakeoil.crt
cp: overwrite ‘../assets/server/tls/snakeoil.crt’? y
[root@VM_175_142_centos ssl]# cp device.key ../assets/server/tls/snakeoil.key
cp: overwrite ‘../assets/server/tls/snakeoil.key’? yngrok
,我们先编译一个1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<!--linux服务端/客户端-->
GOOS=linux GOARCH=386 make release-server (32位)
GOOS=linux GOARCH=amd64 make release-server(64位)
GOOS=linux GOARCH=386 make release-client (32位)
GOOS=linux GOARCH=amd64 make release-client(64位)
<!--Mac OS服务端/客户端-->
GOOS=darwin GOARCH=386 make release-server
GOOS=darwin GOARCH=amd64 make release-server
GOOS=darwin GOARCH=386 make release-client
GOOS=darwin GOARCH=amd64 make release-client
<!--windows服务端/客户端-->
GOOS=windows GOARCH=386 make release-server
GOOS=windows GOARCH=amd64 make release-server
GOOS=windows GOARCH=386 make release-client
GOOS=windows GOARCH=amd64 make release-clientlinux
运行的服务端第一次执行命令时会下载包,所以会比较花时间,可以通过在环境变量中加入1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30[root@VM_175_142_centos ngrok-master]# export GOOS=linux
[root@VM_175_142_centos ngrok-master]# export GOARCH=amd64
[root@VM_175_142_centos ngrok-master]# make release-server
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
-debug=false \
-o=src/ngrok/client/assets/assets_release.go \
assets/client/...
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
-debug=false \
-o=src/ngrok/server/assets/assets_release.go \
assets/server/...
go get -tags 'release' -d -v ngrok/...
github.com/rcrowley/go-metrics (download)
get "gopkg.in/inconshreveable/go-update.v0": found meta tag get.metaImport{Prefix:"gopkg.in/inconshreveable/go-update.v0", VCS:"git", RepoRoot:"https://gopkg.in/inconshreveable/go-update.v0"} at //gopkg.in/inconshreveable/go-update.v0?go-get=1
gopkg.in/inconshreveable/go-update.v0 (download)
github.com/kardianos/osext (download)
github.com/kr/binarydist (download)
get "gopkg.in/inconshreveable/go-update.v0/check": found meta tag get.metaImport{Prefix:"gopkg.in/inconshreveable/go-update.v0", VCS:"git", RepoRoot:"https://gopkg.in/inconshreveable/go-update.v0"} at //gopkg.in/inconshreveable/go-update.v0/check?go-get=1
get "gopkg.in/inconshreveable/go-update.v0/check": verifying non-authoritative meta tag
get "gopkg.in/yaml.v1": found meta tag get.metaImport{Prefix:"gopkg.in/yaml.v1", VCS:"git", RepoRoot:"https://gopkg.in/yaml.v1"} at //gopkg.in/yaml.v1?go-get=1
gopkg.in/yaml.v1 (download)
github.com/inconshreveable/go-vhost (download)
github.com/alecthomas/log4go (download)
github.com/nsf/termbox-go (download)
github.com/mattn/go-runewidth (download)
github.com/gorilla/websocket (download)
go install -tags 'release' ngrok/main/ngrokdGOPROXY
值为https://mirrors.aliyun.com/goproxy/
的方式来添加代理。我继续编译一个windows 64
的客户端现在,我们可以在bin目录下看到这些文件1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@VM_175_142_centos ngrok-master]# export GOOS=windows
[root@VM_175_142_centos ngrok-master]# export GOARCH=amd64
[root@VM_175_142_centos ngrok-master]# make release-client
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
-debug=false \
-o=src/ngrok/client/assets/assets_release.go \
assets/client/...
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
-debug=false \
-o=src/ngrok/server/assets/assets_release.go \
assets/server/...
go get -tags 'release' -d -v ngrok/...
go install -tags 'release' ngrok/main/ngrok先把服务端运行起来,默认情况下1
2
3
4
5
6
7[root@VM_175_142_centos bin]# tree
.
|-- go-bindata
|-- ngrokd
`-- windows_amd64
`-- ngrok.exengrok
是占用的80
和443
端口,我们可以自行配置现在,我们新建一个客户端配置文件1
2
3
4
5
6
7[root@VM_175_142_centos bin]# ./ngrokd -domain="ngrok.52fx.biz" -httpAddr=":8888" -httpsAddr=":8433"
[14:08:59 CST 2020/04/23] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[14:08:59 CST 2020/04/23] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8888
[14:08:59 CST 2020/04/23] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:8433
[14:08:59 CST 2020/04/23] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
[14:08:59 CST 2020/04/23] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 secondsngrok.cfg
现在就可以在客户端运行代理了,1
2
3<!--配置服务端连接地址,也就是基础域名。端口则与服务端-tunnelAddr配置相同-->
server_addr: "ngrok.52fx.biz:4443"
trust_host_root_certs: falsengrok -config=ngrok.cfg -subdomain 域名 端口
,如ngrok -config=ngrok.cfg -subdomain weixin 8080
执行完成之后会看到这样的界面
这里我们还需要配置域名,切记,需要配置两条
- ngrok.52fx.biz-> xxx.xx.xxx.xxx(外网IP)
- *.ngrok.52fx.biz-> xxx.xx.xxx.xxx(外网IP) 该记录为泛解析,就是这样的域名都会解析到指定的ip然后再转发
现在我们来访问一下看是否正常
ok,就是这么回事。但是呢,我们这里的端口是8888,每次访问还得在域名后面加端口,真的是太不优雅了,所以得想办法处理。因为我之前的80端口被nginx给占用了,所以,我们这里再来转发一次吧。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23server {
listen 80;
server_name *.ngrok.52fx.biz;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Nginx-Proxy true;
proxy_set_header Connection "";
proxy_pass http://weixin.ngrok.52fx.biz:8888; #这里的weixin可以改为任意名称,因为是泛解析
}
location ~ .*\.(js|css)$ {
proxy_pass http://weixin.ngrok.52fx.biz:8888; #这里的weixin可以改为任意名称,因为是泛解析
}
}
这样看起来是不是更友好一些了呢?如果你的ngrok
是监听的80端口,大可不必这样麻烦。
老叔教你亲手搭建一个Ngrok内网穿透服务器