这篇文档以实际上线的项目为例, 对Ngrok进行简单的介绍. 希望读者能够举一反三, 毕竟具体的项 目需要读者自己去实践以加深体验.

下面, 我将从’内网穿透概述’, ‘ngrok原理及适用场景’, ‘团队诉求’, ‘ngrok编译使用’, ‘ngrok与Nginx配合使用’几个方面进行展开, 对于了解原理的读者, 请直接查看’ngrok编译使用’ 以及之后的内容即可.

内网穿透概述

当我们开始叙述内网穿透时, 我想首先介绍内网是什么. 为什么我们平时使用的是内网. 让我们先来看一张图.

当你访问http://www.baidu.com时, 我们的目的地是这个网站, 但是在网络请求过程中, 首先要 经过NAT服务器, 当然这种服务器可能不止一台, 这需要看运营商的情况.

ngrok原理以及适用场景

团队诉求

作为校内团队, 我们一致致力于为学生提供优质的服务.

许多需要校内网才能访问的服务, 我们在内网中的服务器进行了汇总, 并且提供RESTfule接口. 这些 暴露并且允许外网访问的服务器一旦遭遇某些特殊情况, 很可能会受到影响从而无法正常提供服务. 此种 不可抗力并非针对我们系统, 但是在一些方面确实造成了诸多不便.

所幸这样的情况并不多, 而且, 处于校内的服务器是可以访问校外的网络, 这为我们问题的解决提供了 一种思路, 利用内网穿透, 可以将某些服务进行外网映射, 临时解决问题.

准备工作

确保你有独立的域名以及公网IP, 后文中将以域名myseu.cn为例进行讲解.

添加域名A记录

Ngrok需要在外网建立服务, 所以, 内网的服务器需要查找域名来查询服务器IP

你需要添加两条域名A记录(均指向你的公网服务器IP):

域名A记录 作用
ngrok.myseu.cn 客户端寻找服务端
*.ngrok.myseu.cn 提供子域名服务

下载编译ngrok

下面可能要贴许多代码了, 其中, 许多代码的意义也许并不那么明了, 如果有兴趣了解, 可以查阅之后 的参考资料, 英文版的资料, 每一步都有详细解释.

下载:

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

编译:

1
2
3
4
5
6
7
8
9
10
11
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=ngrok.myseu.cn" -days 5000 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=ngrok.myseu.cn" -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 release-client

结果查看:

1
2
3
☁  ngrok [master] ⚡ cd bin 
☁ bin [master] ⚡ ls
go-bindata ngrok ngrokd

简单部署

部署分为服务器端与客户端,

首先需要部署服务器端:

  • 1.将文件传至服务器/tmp目录
1
2
☁  ngrok [master] ⚡scp bin/ngrokd heraldnew:/tmp
☁ ngrok [master] ⚡scp assets/server/tls/snakeoil.* heraldnew:/tmp
  • 2.登录服务器启动监听
1
2
3
4
5
6
➜  /tmp ./ngrokd -tlsKey=snakeoil.key  -tlsCrt=snakeoil.crt -domain="ngrok.myseu.cn" -tunnelAddr=":5555" -httpAddr=":8988" -httpsAddr=":8989"
[21:18:03 CST 2017/08/02] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[21:18:03 CST 2017/08/02] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8988
[21:18:03 CST 2017/08/02] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:8989
[21:18:03 CST 2017/08/02] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:5555
[21:18:03 CST 2017/08/02] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds

部署客户端:

  • 1.新建配置文件(后文参考中有配置文件)ngrok.cfg
1
2
server_addr: "ngrok.myseu.cn:5555"
trust_host_root_certs: false
  • 2.建立连接
1
2
3
4
5
6
7
8
☁  bin [master] ⚡ ./ngrok -subdomain he -config=ngrok.cfg 80
ngrok (Ctrl+C to quit)

Tunnel Status online
Version 1.7/1.7
Forwarding https://he.ngrok.myseu.cn:8988 -> 127.0.0.1:80
Forwarding http://he.ngrok.myseu.cn:8988 -> 127.0.0.1:80
Web Interface 127.0.0.1:4040

示例中将本机的80端口分别进行了映射. 至此内网转发结束, 接下来需要配置外网服务器.

ngrok与Nginx配合使用

如果我们的目标如果只是进行端口转发的话, 那么工作已经结束. 但是我们需要对外提供接口, 并且该 接口使用外网服务器的Nginx进行反向代理, 也就是说, 距离真正的服务提供, 我们还差了一个Nginx.

假设我们使用的是直接反向代理, 如下:

1
2
3
location /api {
proxy_pass http://127.0.0.1:8988/api;
}

上线前请你一定要进行测试. 通过测试你会发现, 请求API时会有这样的问题Tunnel xxx not found.

此处Nginx配置决不能这么简单. 代理转发时, 实际是Nginx向后端进行请求, 请求头会被自动填充, 这时的后端就无法进行识别了, 这里我们需要手动修改, 恢复其原始状态

1
2
3
4
5
6
7
8
9
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host tyx.ngrok.myseu.cn:8988; #此处端口要跟 启动服务端ngrok时指定的端口一致
proxy_set_header X-Nginx-Proxy true;
proxy_set_header Connection "";

proxy_pass http://tyx.ngrok.myseu.cn:8988/api;
}

参考资料:

Run Ngrok on Your Own Server Using Self-Signed SSL Certificate 搭建自己的ngrok服务 ngrok 使用上的注意事项

LICENSE:

Copyright © 2017 corvo. 未经许可不得用于商业用途. 转载请注明出处.