内网穿透技术:部署ngrok服务

2018-07-28 2660 0

[update] 另一个替代品(貌似服务端有内存泄露问题):https://github.com/fatedier/frp

什么是ngrok?

ngrok是一个反向代理,它能够让你本地的web服务或tcp服务通过公共的端口和外部建立一个安全的通道,使得外网可以访问本地的计算机服务。 也就是说,我们提供的服务(比如web站点)无需搭建在外部服务器,只要通过ngrok把站点映射出去,别人即可直接访问到我们的服务。

从源码安装ngrok

ngrok目前开源版本是1.7,2.x版本已经不再开源,可以访问 https://ngrok.com/ 使用他们的免费服务(免费服务器位于美国)。

如果觉得速度太慢,可以使用如下脚本自己部署ngrok服务:

  1. sudo yum install golang
  2. git clone --depth=1 https://github.com/inconshreveable/ngrok.git
  3. cd ngrok
  4. # 生成域名证书
  5. export NGROK_DOMAIN="ishield.cn"
  6. openssl genrsa -out rootCA.key 2048
  7. openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem
  8. openssl genrsa -out server.key 2048
  9. openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
  10. openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 5000
  11. # 替换证书
  12. cp rootCA.pem assets/client/tls/ngrokroot.crt
  13. cp server.crt assets/server/tls/snakeoil.crt
  14. cp server.key assets/server/tls/snakeoil.key
  15. #交叉编译,linux系统GOOS=linux,64位系统GOARCH=amd64,32位系统GOARCH=386
  16. #当前系统可用go env查看
  17. GOOS=linux GOARCH=amd64
  18. make release-server
  19. # Linux客户端
  20. COOS=linux GOARCH=amd64 make release-client
  21. # Mac客户端
  22. GOOS=darwin GOARCH=amd64 make release-client
  23. # arm客户端
  24. GOOS=linux GOARCH=arm make release-client

生成服务端和客户端之后,使用下面的命令启动服务端

  1. bin/ngrokd -domain="ishield.cn" -httpAddr=":8088" -httpsAddr=":8089"

首先在你的域名服务商(如DNSPOD)将域名ngrok.ishield.cn指向你的服务器地址。随后将客户端拷贝到你的本机,编译配置文件 ~/.ngrok

  1. server_addr: "ishield.cn:4443"
  2. trust_host_root_certs: false
  3. tunnels:
  4. ssh:
  5. remote_port: 50022
  6. proto:
  7. tcp: 22
  8. vnc:
  9. remote_port: 5902
  10. proto:
  11. tcp: 5902
  12. www:
  13. subdomain: test
  14. proto:
  15. http: 80

然后启动客户端(可以使用-config /home/ubuntu/.ngrok指定配置文件)

  1. ./ngrok start ssh vnc www
  2. # 获取 start-all 启动全部
  3. ./ngrok start-all

注意事项

httpAddr、httpsAddr 分别是 ngrok 用来转发 http、https 服务的端口,可以随意指定。 ngrokd 还会开一个 4443 端口用来跟客户端通讯(可通过 -tunnelAddr=”:xxx” 指定),如果你配置了 iptables 规则,需要开放这几个端口上的 TCP 协议。同时,客户端配置中指定的端口(50022,5902等)也需要在iptables中开放TCP协议。

使用方法

在客户端上启动三个服务之后,在任意一台机器上使用ssh -p 50022 zhangkai@ishield.cn即可登录本机。

方式http://test.ishield.cn:8088即可访问本机上部署在80端口的http服务。

端口问题(可选)

url 上带上端口通常来说并不会有什么影响,而且通过 nginx 隐藏起来也很简单:

  1. # ngrokd.conf
  2. server {
  3. listen 80;
  4. server_name *.ishield.cn;
  5. proxy_set_header Host $host:8088;
  6. proxy_set_header X-Real-IP $remote_addr;
  7. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  8. location / {
  9. proxy_pass http://127.0.0.1:8088;
  10. proxy_redirect off;
  11. }
  12. }

但是!这里就有一个很烦躁的地方了,ngrokd 里面有一层自己的 Host 处理,于是proxy_set_header Host必须带上 ngrokd 所监听的端口,否则就算请求被转发到对应端口上, ngrokd 也不会正确的处理。

带上端口号又会导致了另一个操蛋的问题:你请求的时候是 test.ishield.cn,你在 web 应用中获取到的 Host 是 test.ishield.cn:8088。如果你的程序里面有基于 Request Host 的重定向,就会被重定向到 test.ishield.cn:8088 下面去。如果没有重定向则不需要担心。

要完美的解决这个端口的问题,就需要让 ngrokd 直接监听 80 端口。

通常来说 VPS 都是双网卡的(一内一外),让 ngrokd 监听外网的 80 实在有些浪费,这个端口还是留给 nginx 比较合理。所以比较理想的方式是:nginx 监听外网 80,ngrokd 监听内网 80,让 nginx 将对应的请求转发到内网 80 上来。

内网 ip: 10.160.xx.xx
外网 ip: 112.124.xx.xx

启动 ngrokd:

  1. bin/ngrokd -domain="ishield.cn" -httpAddr="10.160.xx.xx:80" -httpsAddr="10.160.xx.xx:443"

配置 nginx:

  1. # ngrokd.conf
  2. server {
  3. listen 112.124.xx.xx:80;
  4. server_name *.ishield.cn;
  5. proxy_set_header Host $host;
  6. proxy_set_header X-Real-IP $remote_addr;
  7. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  8. location / {
  9. proxy_pass http://10.160.xx.xx:80;
  10. proxy_redirect off;
  11. }
  12. }

如果你是单网卡,那么还可以通过 docker 来解决: http://www.hteen.cn/docker/docker-ngrok.html

自启动

ubuntu16.04的使用systemd来管理启动项,可以通过systemd直接开机自启动ngrok或者使用supervisor来管理,使用supervisor方式参考安装supervisor

新建一个/usr/lib/systemd/system/ngrok.service文件:

  1. [Unit]
  2. Description=Ngrok Service
  3. Wants=network-online.target
  4. [Service]
  5. Type=simple
  6. ExecStart=/home/ubuntu/Documents/tools/opt/bin/ngrok -c /home/ubuntu/.ngrok start ssh
  7. Restart=always
  8. StandardOutput=syslog
  9. StandardError=null
  10. [Install]
  11. WantedBy=multi-user.target
  12. Alias=ngrok.service

使用sudo systemctl enable ngrok将其添加到自启动项。

(可选)启动网络服务sudo systemctl enable NetworkManager-wait-online