Fork me on GitHub
ookamiAntD's Blog

VPS自搭建Ngrok内网穿透服务

前言

Ngrok可以干嘛?我们经常会有 “把本机开发中的 web 项目给朋友看一下” 或 “测试一下支付宝、微信的支付功能” 这种临时需求, 为此专门购买个域名然后在 VPS或云主机 上部署一遍就有点太浪费了. 那么这时候, Ngrok就是个很好的东西, 它可以实现我们的这种需求. 而且 Ngrok 官网本身还提供了公共服务, 只需要注册一个帐号, 运行它的客户端, 就可以快速把内网映射出去. 不过这么好的服务, 没多久就被了~幸好Ngrok是开源的, 那么我们可以自己搭建一个Ngrok!

域名泛解析

因为内网穿透需要用到多级域名, 这里, 博主的这个域名是在Namesilo购买的, 然后转到DNSPod解析:

如图所示, 我搞买的域名是yangbingdong.com,将ngrok.yangbingdong.com通过A记录解析导VPS的ip地址, 再将*.ngrok.yangbingdong.com通过CNAME解析导ngrok.yangbingdong.com, 完成泛解析.

服务端安装

安装GO环境

这里博主选择通过下载最新版解压安装.

1
2
3
4
5
6
7
8
9
apt-get update
apt-get -y install build-essential mercurial git
wget https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
mkdir $HOME/go
echo 'export GOROOT=/usr/local/go' >> /etc/profile.d/go.sh
echo 'export GOPATH=$HOME/go' >> /etc/profile.d/go.sh
echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /etc/profile.d/go.sh
source /etc/profile.d/go.sh

安装Ngrok

1
2
3
cd /usr/local/src/
git clone https://github.com/tutumcloud/ngrok.git ngrok
export GOPATH=/usr/local/src/ngrok/

生成自签名SSL证书, ngrok为ssl加密连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
cd ngrok
NGROK_DOMAIN="ngrok.yangbingdong.com"
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -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 5000
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt
cp device.key assets/server/tls/snakeoil.key
GOOS=linux GOARCH=amd64
make clean
make release-server release-client

注意: 上面的ngrok.yangbingdong.com换成自己的域名.

  • 如果是32位系统,GOARCH=386; 如果是64为系统, GOARCH=amd64
  • 如果要编译linux,GOOS=linux;如果要编译window,GOOS=windows

启动server

1
cd /usr/local/src/ngrok/bin && ./ngrokd -domain="ngrok.yangbingdong.com" -httpAddr=":8002" -httpsAddr=":8003" -tunnelAddr=":4000"

ngrok.yangbingdong.com换成自己的域名. 其他端口可自己配置.
顺利的话, 可以正常编译, 在bin下面可以看到「ngrokd」和「ngrok」, 其中「ngrokd」是服务端执行程序, 「ngrok」是客户端执行程序

后台运行:

1
cd /usr/local/src/ngrok/bin && nohup ./ngrokd -domain="ngrok.yangbingdong.com" -httpAddr=":8002" -httpsAddr=":8003" -tunnelAddr=":4000"  > /dev/null 2>&1 &
1
2
3
4
5
6
apt-get install screen
screen -S 任意名字(例如: keepngork)
然后运行ngrok启动命令
最后按快捷键
ctrl+A+D
既可以保持ngrok后台运行

设置开机启动

1
2
3
4
5
vim /etc/init.d/ngrok_start:
cd /usr/local/src/ngrok/bin
./ngrokd -domain="ngrok.yangbingdong.com" -httpAddr=":8002" -httpsAddr=":8003" -tunnelAddr=":4000"

chmod 755 /etc/init.d/ngrok_start

客户端使用

下载客户端

1
scp -P 26850 root@12.34.56.78:/usr/local/src/ngrok/bin/ngrok ~/

12.34.56.78换成自己的VPS ip.

启动客户端

写一个简单的配置文件, 随意命名如 ngrok.cfg:

1
2
server_addr: ngrok.yangbingdong.com:4000
trust_host_root_certs: false

然后启动:

1
./ngrok -subdomain ybd -config=ngrok.cfg 8080

其中ybd是自定义的域名前缀, ngrok.cfg是上面创建的配置文件, 8080是本地需要映射到外网的端口.
没有意外的话访问ybd.ngrok.yangbingdong.com:8002就会映射到本机的8080端口了.

控制台:

就是上图的Web Interface, 通过这个界面可以看到远端转发过来的 http 详情, 包括完整的 request/response 信息, 相当于附带了一个抓包工具.

另外, Ngrok支持多种协议, 启动的时候可以指定通过-proto指定协议, 例如:

http协议:

1
./ngrok -subdomain ybd -config=ngrok.cfg -proto=http 8080

tcp协议:

1
./ngrok -subdomain ybd -config=ngrok.cfg -proto=tcp 8080

应该会看到:

1
2
3
4
5
6
7
8
ngrok                                               (Ctrl+C to quit)

Tunnel Status online
Version 1.7/1.7
Forwarding tcp://ybd.ngrok.yangbingdong.com:8002-> 127.0.0.1:8080
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms

常见错误

在ngrok目录下执行如下命令, 编译ngrokd

1
2
3
4
5
6
7
8
9
10
11
12
13
$ make release-server

出现如下错误:
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-bindata被安装到了$GOBIN下了, go编译器找不到了. 修正方法是将$GOBIN/go-bindata拷贝到当前ngrok/bin下.

$cp /home/ubuntu/.bin/go14/bin/go-bindata ./bin

遇到的问题: source与./

写了一个Ngrok的安装脚本, 然后chmod +x ngrok-installation.sh赋权, 再./ngrok-installation.sh执行.
但是遇到了一个奇怪的问题: 在脚本里面设置了环境变量并source让其生效, 然而出现的结果是由于没有加载到环境变量导致找不到命令, 百思不得解, Google了一把, 发现了原因:

source命令与shell scripts的区别是:
我们在test.sh设置了AA环境变量, 它只在fork出来的这个子shell中生效, 子shell只能继承父shell的环境变量, 而不能修改父shell的环境变量, 所以test.sh结束后, 父进程的环境就覆盖回去.
source在当前bash环境下执行命令, 而scripts是启动一个子shell来执行命令. 这样如果把设置环境变量(或alias等等)的命令写进scripts中, 就只会影响子shell,无法改变当前的BASH,所以通过文件(命令列)设置环境变量时, 要用source 命令.

然后直接source ngrok-installation.sh, 安装成功!

Docker 搭建 Ngrok

安装Docker请看这里

构建镜像

1
2
3
git clone https://github.com/hteen/docker-ngrok.git
cd docker-ngrok
docker build -t hteen/ngrok .

运行镜像

1
2
3
4
docker run -idt --name ngrok-server \
-p 8082:80 -p 4432:443 -p 4443:4443 \
-v /root/docker/ngrok/data:/myfiles \
-e DOMAIN='ngrok.yangbingdong.com' hteen/ngrok /bin/sh /server.sh
  • -p: 80端口为http端口, 433端口为https端口, 4443端口为tunnel端口
  • -v: 生成的各种配置文件和客户端都在里面
  • -e: 泛化的域名

稍等片刻, 会在挂在的目录(/root/docker/ngrok/data)下面生成对应的配置文件以及客户端

1
2
3
4
bin/ngrokd                  服务端
bin/ngrok linux客户端
bin/darwin_amd64/ngrok osx客户端
bin/windows_amd64/ngrok.exe windows客户端

注意: 大概每个星期会产生100M的日志文件.
查年docker日志文件位置docker inspect <id> | grep LogPath
查看大小ls -lh /var/lib/docker/containers/<id>/<id>-json.log

自构 Docker 镜像

最好是一台境外的服务器(下载速度快)

Dockerfile:

1
2
3
4
5
6
7
8
FROM golang:1.14.6-alpine
ADD build.sh /
RUN apk add --no-cache git make openssl
RUN git clone https://github.com/inconshreveable/ngrok.git --depth=1 /ngrok
RUN sh /build.sh
EXPOSE 8081
VOLUME [ "/ngrok" ]
CMD [ "/ngrok/bin/ngrokd"]

build.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export NGROK_DOMAIN="xxx.yangbingdong.com"
cd /ngrok/
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -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 5000
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt
cp device.key assets/server/tls/snakeoil.key

make release-server
GOOS=linux GOARCH=386 make release-client
GOOS=linux GOARCH=amd64 make release-client
GOOS=windows GOARCH=386 make release-client
GOOS=windows GOARCH=amd64 make release-client
GOOS=darwin GOARCH=386 make release-client
GOOS=darwin GOARCH=amd64 make release-client
GOOS=linux GOARCH=arm make release-client

注意, 需要把上面的 NGROK_DOMAIN 修改为你自己的域名

构建:

1
docker build -t ngrok .

运行:

1
docker run --name=ngrok -it  -p 8081:80 -p 8082:8082 -p 4443:4443  -d yangbingdong/ngrok:stable /ngrok/bin/ngrokd -domain="ngrok.yangbingdong.com" -httpAddr=":80" -httpsAddr=":8082" -tunnelAddr=":4443"

拿到客户端:

1
docker cp ngrok:/ngrok/bin ./
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.
├── darwin_386
│   └── ngrok
├── darwin_amd64
│   └── ngrok
├── go-bindata
├── linux_386
│   └── ngrok
├── linux_arm
│   └── ngrok
├── ngrok
├── ngrokd
├── windows_386
│   └── ngrok.exe
└── windows_amd64
└── ngrok.exe

反向代理

Nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 80;
server_name *.ngrok.yangbingdong.com;
location / {
proxy_redirect off;
proxy_set_header Host $http_host:8081; #此处端口要跟 启动服务端 ngrok 时指定的端口一致
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://172.17.0.1:8081;
}
}
server {
listen 443;
server_name *.ngrok.yangbingdong.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://172.17.0.1:4432;
}
}
  • 172.17.0.1为内网ip

Caddy

Caddyfile:

1
2
3
4
5
6
7
8
http://*.ngrok.yangbingdong.com {
proxy / http://172.17.0.1:8081 {
header_upstream Host {host}:8081 #此处端口要跟 启动服务端 ngrok 时指定的端口一致
header_upstream X-Real-IP {remote}
header_upstream X-Forwarded-For {remote}
header_upstream X-Forwarded-Proto {scheme}
}
}

Finally

另外一个内网穿透工具: frp

---------------- The End ----------------
ookamiAntD wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
谢谢大爷~

Author:ookamiAntD Yang
Link:http://yangbingdong.com/2017/self-hosted-build-ngrok-server/
Contact:yangbingdong1994@gmail.com
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布
转载请注明出处,谢谢!

分享到: