[原创]搭建自己的 Ngrok 服务器, 并与 Nginx 并存

Ngrok 是一个内网穿透工具, 用来将内网的一些服务器暴露到公网上, 目前支持 HTTP 和 TCP 端口转发.

Ngrok 官方提供的服务器因为一些原因导致可用率不高, 但是他们开源了 1.x 版本的服务器端代码(目前最新是 1.7), 这样就可以自己搭建了.

Ngrok Server 端部署

这个比较简单, 参考官方的文件就可以, 步骤无非就是: 拿到代码, 安装 go, 进行编译.

文档地址: https://github.com/inconshreveable/ngrok/blob/master/docs/DEVELOPMENT.md

编译完成后, 执行 ngrokd -h, 输出如下:

Usage of bin/ngrokd:
  -domain="ngrok.com": Domain where the tunnels are hosted
  -httpAddr=":80": Public address for HTTP connections, empty string to disable
  -httpsAddr=":443": Public address listening for HTTPS connections, emptry string to disable
  -log="stdout": Write log messages to this file. 'stdout' and 'none' have special meanings
  -log-level="DEBUG": The level of messages to log. One of: DEBUG, INFO, WARNING, ERROR
  -tlsCrt="": Path to a TLS certificate file
  -tlsKey="": Path to a TLS key file
  -tunnelAddr=":4443": Public address listening for ngrok client

参数比较简单, 指定域名, http 端口, 日志, ssl 证书, 隧道端口.
这里有个问题就是, 80, 443 已经让给 nginx 使用了, 虽然 ngrok 能指定到其它端口, 但是在客户端连接后:

QQ20150903-2@2x.png

一个是 https 识别错误, 一个是访问的时候加端口麻烦, 就算用 nginx 再次代理, 但是客户端显示的端口是没有变化的.

Docker 部分

如果你的服务器有多个 IP, 也可以 Nginx 和 Ngrok 分别监听不同的 IP, 就可以省去 Docker 了.

然后我想到了 Docker, 既然服务端给什么端口, 客户端就显示什么端口, 那么就用 Docker 来欺骗 Ngrok 好了.
找了下 Docker Hub, 大部分都是客户端, 部分服务器端也不是很满意, 那就自己写了个 Dockerfile 编译下吧:

FROM ubuntu:14.04

MAINTAINER fengqi lyf362345@gmail.com

ENV NGROK /opt/ngrok
ENV DOMAIN ngrok.fengqi.me

EXPOSE 80 443 4443

COPY run.sh $NGROK/
COPY bin/ngrokd $NGROK/
COPY ngrok.fengqi.me.crt $NGROK/ssl.crt
COPY ngrok.fengqi.me.key $NGROK/ssl.key

RUN chmod +x $NGROK/run.sh

CMD $NGROK/run.sh

run.sh 内容:

#!/bin/bash

/opt/ngrok/ngrokd -tlsCrt /opt/ngrok/ssl.crt -tlsKey /opt/ngrok/ssl.key -domain ngrok.fengqi.me

内容比较简单, 以 Ubuntu 14 构建, 然后把外面编译好的 Ngrokd 和 SSL 证书复制进去.

我的 SSL 是用的免费证书, 没有通配版, 所以 https://*.ngrok.fengqi.me 是自签名证书.
如果你想测试我提供的 https, 需要先本地安装并信任我的跟证书 Fengqi Global CA
我在自签名证书时, 全部是使用这个跟证书颁发, 所以只需要本地信任一次就可以了.

然后在放 Dockerfile 的目录下运行 docker build -t fengqi/ngrokd . 等等执行完成.
执行 docker images 查看下现在的容器:

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
fengqi/ngrokd       latest              fdf8ca983ed9        1 minutes ago      198.4 MB
ubuntu              14.04               91e54dfb1179        13 days ago         188.4 MB

可以看到已经正常编译完成, 然后启动这个容器:

docker run -d -p 127.0.0.1:8080:80 -p 127.0.0.1:8081:443 -p 4443:4443 fengqi/ngrokd:latest

这里把容器里的80, 443, 4443 端口映射到本地, 后面再通过 Nginx 反代提供到公网.
检验下效果:

root@fengqi-Vultr:~# telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^]quit

telnet> quit
Connection closed.
root@fengqi-Vultr:~# telnet 127.0.0.1 8081
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^]quit

telnet> quit
Connection closed.
root@fengqi-Vultr:~# telnet 127.0.0.1 4443
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^]quit

telnet> quit
Connection closed.

看起来没什么问题.

Nginx 部分

Nginx 只需要建立一个 http server, 把请求转发到 Docker 里面的 Ngrokd 就行了.

map $scheme $proxy_port {
    "http"  "8080";
    "https" "8081";
    default "8080";
}

server {
    listen      80;
    listen      [::]:80;
    listen      443;
    listen      [::]:443;
    server_name ngrok.fengqi.me *.ngrok.fengqi.me;

    location / {
        proxy_pass  $scheme://127.0.0.1:$proxy_port;
    }

    ssl on;
    ssl_certificate /opt/ngrok/ngrok.fengqi.me.crt;
    ssl_certificate_key /opt/ngrok/ngrok.fengqi.me.key;

    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    Host $http_host;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;

    access_log off;
    log_not_found off;
}

这里没有做什么优化, 就是转发下请求. 这时客户端再次链接时就正常了:

QQ20150903-3@2x.png

因为需要开机就启动这个容器, 可以把启动命令放到 /etc/rc.local 里面.

使用第三方 Ngrok 服务器

使用我提供的 Ngrok 服务器的方法是, 在 ~/.ngrok 下写入以下内容:

server_addr: "ngrok.fengqi.me:4443"
trust_host_root_certs: true

标签: nginx, docker, ngrok

已有 11 条评论

  1. fushall fushall

    请问,我想在服务器上使用ngrok客户端生成的https,来达到内网搭建https,外网通过域名访问https,只要我监听相应端口(按照本文,应该是80端口)就可以了吗?

    1. 对的, https 由 ngrok 来

  2. Vv Vv

    相当感谢,这个帖子帮助我解决了大问题,并且开始学习了docker 真是入了深坑了。

  3. cena cena

    请问下大神,linux下需要安装证书?

    1. 对,因为四级子域是不固定的,所以需要通配符,但是我的 SSL 证书是免费版不支持通配符,所以只能自颁发了。

  4. RonaldWhite RonaldWhite

    非常感谢, 解决大问题了!

    1. 不用客气 :-)

  5. sam sam

    你好 windows下如何使用你的ngrok服务呢?

    1. 一样的,下载 win 的客户端,安装我的证书,cmd 下运行命令就好了。

  6. goofansu goofansu

    非常感谢,配置好了很方便,省了一台服务器和一个ip地址

    1. 不用客气 :-)

添加新评论