ngrok 支持 https

  • 需要一个公网带固定 IP 的服务器
  • 需要一个域名

域名以 *.ngrok.coding.gsngrok.coding.gs 为例

目录

  1. 安装 ngrok
  2. 申请免费 https 证书
  3. 启动支持 https 的 ngrok

安装 ngrok

添加 DNS 解析

添加两条 A 记录 *.ngrok.coding.gsngrok.coding.gs 指向服务器的 IP

安装开发环境

$ sudo apt-get install -y golang vim git
$ go env
$ export GOPATH=$HOME/go
$ PATH=$PATH:$HOME/.local/bin:$HOME/bin:$GOPATH/bin
$ mkdir -p  ~/go/src/github.com/inconshreveable
$ cd ~/go/src/github.com/inconshreveable
$ git clone https://github.com/inconshreveable/ngrok.git
$ export GOPATH=~/go/src/github.com/inconshreveable/ngrok

生成自签名证书

域名以 *.ngrok.coding.gsngrok.gs为例

$ cd ngrok
$ openssl genrsa -out rootCA.key 2048
$ openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=ngrok.coding.gs" -days 5000 -out rootCA.pem
$ openssl genrsa -out device.key 2048
$ openssl req -new -key device.key -subj "/CN=ngrok.coding.gs" -out device.csr
$ openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000

执行完生成证书的命令,会在当前目录生成 6 个文件

➜  ngrok git:(master) ✗ ls -al
total 76
drwxr-xr-x 7 coding coding 4096 Jul 16 14:44 .
drwxr-xr-x 3 coding coding 4096 Jul 16 14:39 ..
drwxr-xr-x 4 coding coding 4096 Jul 16 14:39 assets
drwxr-xr-x 2 coding coding 4096 Jul 16 14:39 contrib
-rw-r--r-- 1 coding coding  199 Jul 16 14:39 CONTRIBUTORS
-rw-r--r-- 1 coding coding  993 Jul 16 14:44 device.crt
-rw-r--r-- 1 coding coding  899 Jul 16 14:44 device.csr
-rw-r--r-- 1 coding coding 1675 Jul 16 14:44 device.key
drwxr-xr-x 2 coding coding 4096 Jul 16 14:39 docs
drwxr-xr-x 8 coding coding 4096 Jul 16 14:44 .git
-rw-r--r-- 1 coding coding  150 Jul 16 14:39 .gitignore
-rw-r--r-- 1 coding coding  551 Jul 16 14:39 LICENSE
-rw-r--r-- 1 coding coding 1433 Jul 16 14:39 Makefile
-rw-r--r-- 1 coding coding 2725 Jul 16 14:39 README.md
-rw-r--r-- 1 coding coding 1679 Jul 16 14:43 rootCA.key
-rw-r--r-- 1 coding coding 1111 Jul 16 14:43 rootCA.pem
-rw-r--r-- 1 coding coding   17 Jul 16 14:44 rootCA.srl
drwxr-xr-x 3 coding coding 4096 Jul 16 14:39 src
-rw-r--r-- 1 coding coding  156 Jul 16 14:39 .travis.yml

用新生成的证书替换原本的证书

$ 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 # 编译服务端
$ make release-client # 编译客户端


$ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 make release-client # 编译 Windows 客户端
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 make release-server   # 编译 Linux 服务端

# 其他平台
# Linux 平台 32 位系统:GOOS=linux GOARCH=386
# Linux 平台 64 位系统:GOOS=linux GOARCH=amd64
# 
# Windows 平台 32 位系统:GOOS=windows GOARCH=386
# Windows 平台 64 位系统:GOOS=windows GOARCH=amd64
# 
# MAC 平台 32 位系统:GOOS=darwin GOARCH=386
# MAC 平台 64 位系统:GOOS=darwin GOARCH=amd64
# 
# ARM 平台:GOOS=linux GOARCH=arm

通过上面的步骤,将生成所有客户端文件,客户端文件放在对于的文件夹中,如windows 64位的为:windows_amd64,linux客户端在bin目录下的ngrok文件。当然,也可以简单的使用 $ make release-client 进行编译成默认的ngrok客户端文件。

启动 ngrok

服务端

# 启动 ngrok
$ ./ngrokd -domain="ngrok.coding.gs" -httpAddr=":80" -httpsAddr=":443"
# 可以通过 tunnelAddr 参数替换 ngrok 默认的 4443 端口
$ ./ngrokd -domain="ngrok.coding.gs" -httpAddr=":80" -httpsAddr=":8081" -tunnelAddr=":443"

或者使用 docker

FROM alpine:3.7

COPY ngrokd /ngrokd

RUN ls -al /

EXPOSE 80 443 4443

CMD ["/ngrokd","-domain=ngrok.coding.gs","-httpAddr=:80","-httpsAddr=:443","-tunnelAddr=:4443"]
$ sudo docker build -t haozibi/ngrok .
$ sudo docker run --rm -d -p 80:80 -p 443:443 -p 4443:4443 haozibi/ngrok

本地

新建 ngrok 配置文件,ngrok.cfg,放在 ngrok 可执行文件同一目录中。

客户端ngrok.cfg中server_addr后的值必须严格与-domain以及证书中的NGROK_BASE_DOMAIN相同

server_addr: "ngrok.coding.gs:4443"
trust_host_root_certs: false
$ ls -al
total 12553
drwxr-xr-x 1 Administrator 197121        0 七月 12 18:08 ./
drwxr-xr-x 1 Administrator 197121        0 七月 12 14:45 ../
-rw-r--r-- 1 Administrator 197121       64 七月 16 22:05 ngrok.cfg
-rwxr-xr-x 1 Administrator 197121 12839424 七月 12 14:41 ngrok.exe*
-rw-r--r-- 1 Administrator 197121      257 七月 12 21:27 ngrok启动工具.bat

运行客户端

$ ./ngrok -subdomain haozibi -config=ngrok.cfg 4000
# 启动一个特定的接口
$ ./ngrok -subdomain haozibi -config=[YOUR_CONFIG_FILE_NAME] -proto tcp 3306

或者是编写一个 .bat 脚本方便命令执行

@echo OFF
color 0a
Title Ngrok 启动工具 by haozibi
Mode con cols=109 lines=30
echo.
:TUNNEL
set /p clientid=   请输入需映射前缀:
ECHO.
ECHO.
set /p port=   请输入需映射端口:
echo.
ngrok -config=ngrok.cfg -subdomain %clientid% %port%
PAUSE
goto TUNNEL

具体的详细文档: https://ngrok.com/usage

看到下面则正常运行

运行本地 web 程序,以 Golang 为例

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "haozibi")
        return
    })
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

运行 golang 代码,打开 http://haozibi.ngrok.coding.gs 则可以看到页面正常渲染

而且可以通过 http://127.0.0.1:4040 查看所有请求

申请免费 https 证书

我们申请 Let's Encrypt 免费的泛域名证书,有效期为 3 个月

可以使用 acme.sh 或者 certbot 申请证书,此次以 certbot 做示范

申请的域名根据上面的要求,所以要是 *.ngrok.conding.gsngrok.conding.gs

# 下载
$ wget https://dl.eff.org/certbot-auto

# 设为可执行权限
$ chmod a+x certbot-auto

# 申请证书
$ ./certbot-auto --server https://acme-v02.api.letsencrypt.org/directory -d "*.ngrok.conding.gs" -d "ngrok.conding.gs" --manual --preferred-challenges dns-01 certonly

按照要求填写邮箱(到期提醒)等信息,申请证书要经过DNS认证的,按照提示,前往域名后台添加对应的DNS TXT记录,因为申请的的两个域名所以要添加两次。添加之后,不要心急着按回车,先执行dig xxxx.xxx.com txt确认解析记录是否生效,生效之后再回去按回车确认。

最后证书会保存在 /etc/cert/ngrok.coding.gs/ 文件夹中,会根据使用环境生成多种证书

cert.pem  - Apache服务器端证书
chain.pem  - Apache根证书和中继证书
fullchain.pem  - Nginx所需要ssl_certificate文件
privkey.pem - 安全证书KEY文件

启动支持 https 的 ngrok

服务端

修改启动命令,加上刚申请的证书,注意添加的参数

$ ./ngrokd -domain="ngrok.coding.gs" -httpAddr=":80" -httpsAddr=":443" -tlsCrt="/etc/letsencrypt/live/ngrok.coding.gs/cert.pem" -tlsKey="/etc/letsencrypt/live/ngrok.coding.gs/privkey.pem"

客户端

修改配置文件 trust_host_root_certs 参数为 true 即可,

server_addr: "ngrok.coding.gs:4443"
trust_host_root_certs: true

此时重新运行客户端,https 即生效

证书到期问题

https 证书只有 3 个月的有效期,3个月到期后就要重新续期,而且 ngrok 需要重新启动,所以需要一个脚本和定时任务完成这些操作。

certbotngrokd 复制到 /usr/local/bin/

# 具体路径以实际为准
$ cp certbot-auto /usr/local/bin/
$ cp ngrok /usr/local/bin/

# 在 /usr/local/bin 创建 renew.sh,并添加执行权限
$ chmod +x renew.sh

# 添加 crontab 定时任务,每隔 80 天的凌晨 4 点执行一次 renew:

0 4 */80 * * /usr/local/bin/renew.sh >> /dev/null

renew.sh 具体信息

#!/bin/bash
echo "ngrok renew https by haozibi"

killall ngrokd
certbot-auto renew
nohup ngrokd -domain="ngrok.coding.gs" -httpAddr=":80" -httpsAddr=":443" -tlsCrt="/etc/letsencrypt/live/ngrok.coding.gs/cert.pem" -tlsKey="/etc/letsencrypt/live/ngrok.coding.gs/privkey.pem" >/dev/null 2>&1 &

参考链接