由於專案開發會使用到 LINE 服務,頻繁使用到 webook 和打 API 等動作,這時候在本地開發會遇到一個問題:我的開發環境沒辦法對外,怎麼測試 webhook 和第三方API?這時候 ngrok 工具就會很好用,ngrok 是一種 server relay 的機制,來實現內網穿透。將 ngrok 配置的 domain 映射到你本機 server 的服務端口,如 xxx.ngrok.com -> localhost:80。但是使用官方提供的工具難免會有些限制,像是非會員的部分,1 分鐘內 http session 只能20個以內,超過就會被暫時封鎖(過一段時間會解鎖)。若你想要不受此限制,就可以使用官方提供的 1.x 版 source code 自己編譯 ngrok client/server 。
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
可以寫個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