ngrok source

https://github.com/inconshreveable/ngrok

Pre-required

  • Ubuntu server with public IP (EC2)
  • A public Domain
  • nginx
  • docker, docker-compose

Add record set to your domain

在網域管理底下添加2個A紀錄到你的Domain

  • ngrok.scottchayaa.com
  • *.ngrok.scottchayaa.com

Run ngrok-server on docker

1
2
3
~$ mkdir ngrok-server
~$ cd ngrok-server
~$ vi docker-compose.yml

docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: '3'

services:
  ngrok-server:
    image: hteen/ngrok
    logging:
      driver: "json-file"
      options:
        max-size: "20m"
        max-file: "10"
    ports:
      - "8880:80"
      - "8443:443"
      - "4443:4443"
    volumes:
      - "./data:/myfiles"
    environment:
      - DOMAIN=ngrok.scottchayaa.com # your subdomain
    command: ["/bin/sh", "/server.sh"]
    restart: always
  • 因為 80, 443 比較常使用,所以我們改使用別的 port 來當作 http 和 https
  • 之後會透過 nginx 反向代理來指向 ngrok server 的 http 和 https
  • 4443 port是 ngrok server 與 client 溝通的 port
  • 記得要使用 loggin 限制 container log 數量和大小, ngork 的 log 成長速度很驚人的,之前 Container 運作正常都沒重啟,用了約 5 weeks, log file 成長到 300m 。 詳細設定可參考 docker-compose logging
1
2
# 啟動 ngrok-server
~$ docker-compose up -d
  • 啟動後,build.sh會產生./data 的產物
  • 私有金鑰 base.*, device.* (不重要)
  • /bin : 裡面是 ngrok-clinet的執行程序,且有windows和linux版本 (重要)

/bin 這個因為compile比較久,會比較慢出現

若要重build /data,只要砍掉/data後,重新執行docker-compose即可

Install nginx

1
sudo apt-get install nginx

nginx 反向代理配置

sudo vi /etc/nginx/conf.d/ngrok-proxy.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
server {
    listen 80;
    server_name ngrok.scottchayaa.com *.ngrok.scottchayaa.com;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8880;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }
}
1
2
# restart nginx
sudo service nginx restart

申請 letsencrypt 憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 第一組 : test1.ngrok.scottchayaa.com
~$ docker run --rm -v ~/letsencrypt:/etc/letsencrypt \
-v /var/www/letsencrypt:/html -ti \
certbot/certbot certonly \
--email example@gmail.com \
--agree-tos \
--webroot \
-w /html \
-d test1.ngrok.scottchayaa.com 

# 第二組 : test2.ngrok.scottchayaa.com
~$ docker run --rm -v ~/letsencrypt:/etc/letsencrypt \
-v /var/www/letsencrypt:/html -ti \
certbot/certbot certonly \
--email example@gmail.com \
--agree-tos \
--webroot \
-w /html \
-d test2.ngrok.scottchayaa.com

# 申請多組,以此類推

設定 https

sudo vi /etc/nginx/conf.d/ngrok-proxy-ssl.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 第一組
server {
    listen 443 ssl;
    server_name test1.ngrok.scottchayaa.com;

    ssl_certificate /home/ubuntu/letsencrypt/live/test1.ngrok.scottchayaa.com/fullchain.pem;
    ssl_certificate_key /home/ubuntu/letsencrypt/live/test1.ngrok.scottchayaa.com/privkey.pem;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8880;
   }
}

# 第二組
server {
    listen 443 ssl;
    server_name test2.ngrok.scottchayaa.com;

    ssl_certificate /home/ubuntu/letsencrypt/live/test2.ngrok.scottchayaa.com/fullchain.pem;
    ssl_certificate_key /home/ubuntu/letsencrypt/live/test2.ngrok.scottchayaa.com/privkey.pem;
    
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8880;
   }
}

然後重啟 nginx service

1
sudo service nginx restart

Run ngrok-client on localhost

  • 從你一開始編譯的 ~/ngrok-server/data/bin 裡面下載所需的 ngrok client 版本

  • 配置 ngrok.cfg 設定檔

    1
    2
    
    server_addr: "ngrok.scottchayaa.com:4443"
    trust_host_root_certs: false
    
  • 啟動 ngrok

    1
    2
    3
    4
    
    ./ngrok -config=ngrok.cfg -subdomain=test1 3000
    ./ngrok -config=ngrok.cfg -subdomain=test2 3000
       
    # 可以指定兩組 https
    

可以寫個nodejs http server,port指定3000

執行成功則會顯示

確認憑證是否完整合法
https://www.sslshopper.com/ssl-checker.html

設定自動更新 SSL 憑證

因為假掰使用 docker 的方式來執行 certbot
所以這步驟就麻煩了點

sudo vi /home/ubuntu/letsencrypt/auto-renew

1
2
3
4
5
6
7
8
9
#!/bin/sh
  
logPath=/var/log/certbot.log

echo -e "\n"`date +"%Y-%m-%d %H:%M:%S"`"\n"

sudo docker run --rm -v /home/ubuntu/letsencrypt:/etc/letsencrypt \
-v /var/www/letsencrypt:/html -ti \
certbot/certbot renew >> $logPath 2>&1 && sleep 30 && service nginx reload >> $logPath 2>&1

change permission

1
sudo chmod 755 /home/ubuntu/letsencrypt/auto-renew

create soft link to /etc/cron.weekly

1
ln -s /home/ubuntu/letsencrypt/auto-renew /etc/cron.weekly/auto-renew

[a-zA-Z0-9_-] are the valid characters on run-parts command

這樣一來
每個禮拜 certbot 就會自動檢查並 renew 更新 ssl 憑證

Summary

之前在還沒有使用 ngrok 時
測試 webhook 功能會受限於在測試環境(因為主機有對外)

有了自己的ngrok server後
由於在本機,所以開發和測試上會快速許多
不用 git push 後在那邊等自動部署到測試環境
然後發現有個地方寫錯等等還要重新 commit…等
繁瑣流程會降低開發效率(速度)

本機程式開發最好就是開發與測試環境是可以一致的
頂多就config配置不同

不過,這以上都還是需要依賴網路
最理想的狀況是連網路這個依賴都拔除
這時候就要靠單元測試
以後有機會再來寫單元測試如何應用在專案上的單元

後記

後來有次在使用 ngrok 上傳檔案時遇到 413 Request Entity Too Large 的錯誤
這是你 server 上 nginx 發生的限制錯誤(當時還以為是本機打通的 nginx sevice)
查了一下,主要是要修改 /etc/nginx/nginx.conf 就好
把 upload max size 限制拉到 20M 左右即可(自行控制)

1
client_max_body_size 20M;
1
2
# 重啟 nginx 
sudo service nginx restart

Reference