在lnmp服务器搭建ngrok服务

泛域名SSL证书也太贵了吧

Posted by Donggu Ho on 2017-05-26

动态域名内网穿透是个好东西,没有公网IP/没有服务器的时候就可以使用内网穿透把系统的特定端口暴露出来以在提供公网服务。比如说微信开发时需要的输入自己服务的域名、本地调试https、临时给队友看看懒得部署等乱七八糟的应用场合。

因为调试 Bot Framework 而需要搞一个windows的服务器,Azure只有一个月,腾讯云拼了老命就是没抢到,于是决定把自己的旧本子接上电源放在宿舍当服务器用。虽然宿舍的教育网有公网IP,设置了端口映射之后就基本没问题了,但是公网IP几天一换,就很麻烦。而花生壳(免费版)的域名难记得很还有点慢,主要还是感觉太不geek了。

ngrok倒是非常不错,虽然免费版也不能自定义域名,但是提供https和http的服务,使用也非常简单。唯一的问题是域名随时会换……以及国内访问速度比较糟糕(被墙)。由于 ngrok 1.x 开源,因此国内也有不少提供商做这个,速度明显快很多,但是免费版都不提供https服务和自定义。妈个鸡既然都开源了我干嘛不自己搭一个我又不是没有服务器。

靠自己,你就是女王


环境依赖配置以及下载

服务器: 阿里云乞丐机 CentOS 7.0 64x

配置DNS解析

比如我计划使用ngrok.donggu.me作为提供服务的URL,那么配置好之后就可以分配*.ngrok.donggu.me进行穿透;那么则需要在DNS解析中添加ngrok.donggu.me*.ngrok.donggu.me的A记录,指向服务器IP。

安装 Go 语言依赖

由于 ngrok 是用 Go 写的,因此需要先安装 Go 语言依赖。说起来为什么最近突然认识的项目都在弄 Go

1
2
3
4
5
$ yum install golang
# 配置和应用环境变量
$ echo export GOPATH=\$HOME/go >> ~/.bash_profile
$ echo PATH=\$PATH:\$HOME/.local/bin:\$HOME/bin:\$GOPATH/bin >> ~/.bash_profile
$ source ~/.bash_profile

安装 Git 和 openssl

1
$ yum install git openssl

正常来说以上足矣……但是我突然发现yum库里面的 Git 是1.8.x的,新版早就是2.x了好吗!于是参考这篇文章进行了下载源码手动编译的活。

获取 ngrok

跳转到目标安装目录,比如我希望安装在/usr/local/ngrok

1
2
$ cd /usr/local
$ git clone https://github.com/inconshreveable/ngrok.git ngrok

ngrok的配置

生成自签名证书

看到这里有同学要提问了,阿里云明明是提供20个免费ssl证书的呀为什么要自己弄个假的?主要是……阿里云的免费证书是单域名证书,而ngrok提供的服务是随机分配子域名,想要实现必须使用泛域名证书大概也就四五千软一年吧:),所以用假的就假的吧无所谓了’_>’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cd ngrok
$ NGROK_DOMAIN="ngrok.donggu.me" # 提供服务的URL

# 生成证书
$ openssl genrsa -out rootCA.key 2048
$ openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=ngrok.fex.im" -days 5000 -out rootCA.pem
$ openssl genrsa -out device.key 2048
$ openssl req -new -key device.key -subj "/CN=ngrok.fex.im" -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

Linux客户端:

$ make release-client

Windows客户端:

1
2
3
4
5
6
$ cd /usr/local/go/src/
$ GOOS=windows GOARCH=386 CGO_ENABLED=0 ./make.bash # 32位
$ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./make.bash # 64位
$ cd /usr/local/ngrok
$ GOOS=windows GOARCH=386 make release-client # 32位
$ GOOS=windows GOARCH=amd64 make release-client # 64位

Mac客户端:

1
2
3
4
$ cd /usr/local/go/src/
$ GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 ./make.bash
$ cd /usr/local/ngrok
$ GOOS=darwin GOARCH=amd64 make release-client

树莓派客户端(停一下???):

1
2
3
4
$ cd /usr/local/go/src/
$ GOOS=linux GOARCH=arm CGO_ENABLED=0 ./make.bash
$ cd /usr/local/ngrok
$ GOOS=linux GOARCH=arm make release-client

编译完成后,编译成果会在/usr/ngrok/bin目录下,其中ngrokd为服务端文件。为了方便,可以将该目录加入 PATH 大礼包:

1
2
$ echo PATH=\$PATH:/usr/ngrok/bin >> ~/.bash_profile
$ source ~/.bash_profile

运行服务端

1
2
3
$ ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":8088" -httpsAddr=":8089"
# 后台运行,在后面加个 &
$ ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":8088" -httpsAddr=":8089" &

8088和8089的端口随便设置,别冲突了就好。
运行成功的输出大概长这样:

[17:23:58 CST 2017/05/26] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[17:23:58 CST 2017/05/26] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds
[17:23:58 CST 2017/05/26] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8088
[17:23:58 CST 2017/05/26] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:8089
[17:23:58 CST 2017/05/26] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443

此时直接在浏览器输入任意一个子域名,比如mdzz.ngrok.donggu.me:8088,看到以下提示,则说明服务以及搭建成功:

$ Tunnel mdzz.ngrok.donggu.me:8088 not found

客户端使用

把编译出来的客户端下载到本地,此处以windows为例,其它系统估计除了文件后缀都一样吧……

在客户端同目录下新建一个ngrok.cfg配置文件,写入并保存:

1
2
server_addr: ngrok.donggu.me:4443
trust_host_root_certs: false

然后在命令行该目录下运行:

1
> ngrok.exe -config=ngrok.cfg 4000 # 最后一个是需要内网穿透的本地端口

如果出现类似以下显示即成功。

1
2
3
4
5
6
7
8
ngrok 
Tunnel Status online
Version 1.7/1.7
Forwarding http://53f11330.ngrok.donggu.me:8088 -> 127.0.0.1:4000
Forwarding https://53f11330.ngrok.donggu.me:8088 -> 127.0.0.1:4000
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms

此时通过 ngrok 自动分配的地址(例子中是http://53f11330.ngrok.donggu.me:8088)即可在网上访问本地的localhost:4000。而https,并不能用:)

如果想要自定义子域名的话使用-subdomain指定即可。

1
> ngrok.exe -subdomain=hello -config=ngrok.cfg 8080

这样就可以通过hello.ngrok.donggu.me:8088访问了。
访问本地localhost:4040即可查看ngrok运行状态。

更多命令可以使用ngrok.exe -h查看。

配置 Nginx 端口转发(可选)

访问要加端口还是麻烦啊。但是默认的80端口已经被 Nginx 占掉了,所以需要配置一下 Nginx。添加一个新的调节文件,以下按的是lnmp的路径:

1
2
$ cd /usr/local/nginx/conf/vhost
$ vi ngrok.conf

编辑内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
server_name *.ngrok.donggu.me;
listen 80;
keepalive_timeout 70;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host:8088;
proxy_redirect off;
proxy_pass http://127.0.0.1:8088;
}
access_log off;
log_not_found off;
}

保存后重启 Nginx 即可。

$ lnmp nginx restart

这样就可以不用加url后面的:8088直接干净利落地通过默认端口访问了。

配置泛域名https(可选)

泛域名证书真的太贵了!制作自签名的泛域名证书步骤不难,不过访问的时候浏览器会提示不安全,然后要继续进入什么的。

生成自签名泛域名证书

懒得抄一遍了请直接看这里

配置Nginx

还是前面新建的那个ngrok.conf,在中间多加几句即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
server_name *.ngrok.donggu.me;
listen 80;
# 添加以下四行
listen 443;
ssl on;
ssl_certificate /path/to/your/ngrok.crt; # 上一步生成的网站证书
ssl_certificate_key /path/to/your/ngrok.key; # 上一步生成的网站密钥

keepalive_timeout 70;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host:8088;
proxy_redirect off;
proxy_pass http://127.0.0.1:8088;
}
access_log off;
log_not_found off;
}

然后再次重启Nginx,即可达成。访问URL为https://anything.ngrok.donggu.me,不加端口才行。

为ngrok添加客户验证

ngrok内部留了接口来实现用户authtoken身份验证,用来区分用户权限啊什么的都是好的,主要是防止服务被人玩坏。但是就要自己去写 Go 了。相关博文我随便找了一篇,反正我是懒得搞了……

粉丝福利(大雾

冬菇已经搭好了上述服务,各版本客户端已发布到mdzz.donggu.me上面(ngrok.zip),欢迎内测使用~不过为了防止服务器被玩坏我还是把压缩包加了个密,密码私戳可得【正色