近日實習的公司要作企業微信開發,可是尚未購買固定公網 IP,爲了調試方便我決定在內網搭建一個 ngrok 內網穿透服務。通過兩天左右的踩坑,下面大體記錄一下流程和解決的問題。php
首先固然是要作的準備工做,你須要準備:html
ngrok 代理的端口最後會體現到 url 上,若是你的請求中包含相對路徑,那麼請求將會被重定向到 <your.domain>:<port>
上,而微信的服務只會向 443
端口發請求;而若是 ngrok 直接代理 80
或 443
端口,這意味着你其餘的 web 服務如 nginx 或 apache 服務將沒法使用,這顯然是不容許的。mysql
所以,將 ngrok 放置在 docker 容器中監聽 80
和 443
端口,並對外暴露不一樣的端口號,使用 nginx 進行代理轉發,這樣就能避免上面的問題了。nginx
lnmp 是一個一鍵 nginx + php + mysql 安裝工具,包含了許多有用的工具包 (例如 vhost 管理和域名證書申請),下載安裝很是方便:git
$ wget http://soft.vpser.net/lnmp/lnmp1.5.tar.gz -cO lnmp1.5.tar.gz
$ tar zxf lnmp1.5.tar.gz && cd lnmp1.5
$ [sudo] ./install.sh lnmp
複製代碼
因爲個人服務器內存較小,我選擇跳過了 mysql 安裝並安裝了低版本的 php 環境,您應該根據須要自行選擇;或者您要是熟悉 nginx 的 ssl 配置的話,能夠選擇跳過本章節,手動申請域名並配置代理轉發。github
完成 lnmp 安裝後,可使用它提供的命令來方便的申請泛域名證書,使用下面的命令,按照屏幕上的提示完成配置便可:golang
$ [sudo] lnmp dnsssl
複製代碼
注意保存生成的證書路徑信息,下面會用到。web
若是您是手動在 Let's Encrypt 申請的泛域名證書,那還請注意它的有效期只有三個月,到期還須要手動更新。sql
完成後,lnmp 會幫助您建立一個 nginx vhost 配置文件,位置在 /usr/local/nginx/conf/vhost/<example.your.domain>.conf
,參考下面的配置替換原有內容:docker
map $scheme $ngrok_proxy_port {
"http" "5442";
"https" "5443";
default "5442";
}
server {
listen 80;
listen 443 ssl http2;
#listen [::]:443 ssl http2;
server_name tunnel.your.domain *.tunnel.your.domain;
ssl on;
ssl_certificate /usr/local/nginx/conf/ssl/tunnel.your.domain/fullchain.cer;
ssl_certificate_key /usr/local/nginx/conf/ssl/tunnel.your.domain/tunnel.your.domain.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
ssl_session_cache builtin:1000 shared:SSL:10m;
# openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
location / {
proxy_pass $scheme://127.0.0.1:$ngrok_proxy_port;
}
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;
}
複製代碼
使用 Docker's install script 能夠方便的下載安裝 docker,使用方法:
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ chmod +x ./get-docker.sh
$ ./get-docker.sh
複製代碼
你可能須要輸入 sudo 密碼來獲取管理員權限。國內用戶能夠在 ./get-docker.sh
後面加上 --mirror Aliyun
來使用阿里雲 docker 鏡像。
這裏我參考了 hteen/docker-ngrok 的寫法,不過我不須要在編譯前自簽名 ssl 證書,因此我簡化了他的寫法並優化了鏡像構建過程 (最後生成的鏡像只有 18.7M
😎):
FROM golang:alpine as builder
LABEL maintainer="Mitscherlich <mitscherlich36@gmail.com>" \ provider="hteen <i@hteen.cn>"
COPY . /tmp
# install ngrok dependencies
RUN apk add --no-cache git make
# clone ngrok source code and build binary
RUN git clone https://github.com/inconshreveable/ngrok.git /tmp/ngrok && \ cd /tmp/ngrok && make release-server
FROM alpine
EXPOSE 4443 80 443
ENV NGROK_DOMAIN=${NGROK_DOMAIN} \
NGROK_DIR=/usr/local/ngrok \
TUNNEL_ADDR=":4443" \
HTTP_ADDR=":80" \
HTTPS_ADDR=":443" \
TLS_KEY=${NGROK_DIR}/certs/device.key \
TLS_CRT=${NGROK_DIR}/certs/device.crt
COPY --from=builder /tmp/ngrok/bin ${NGROK_DIR}/bin
VOLUME [ "/usr/local/ngrok/certs" ]
ENTRYPOINT /usr/local/ngrok/bin/ngrokd \ -domain=${NGROK_DOMAIN} \ -tlsKey=${TLS_KEY} \ -tlsCrt=${TLS_CRT} \ -httpAddr=${HTTP_ADDR} \ -httpsAddr=${HTTPS_ADDR} \ -tunnelAddr=${TUNNEL_ADDR} 複製代碼
完成後,使用下面的命令構建鏡像:
$ docker build -t ngrok .
複製代碼
使用也很是簡單,不過您須要將上面生成的 ssl 證書路徑做爲共享卷掛載到 docker 容器中,ngrok 須要能訪問到這些證書:
# 例如個人證書放在 /usr/local/nginx/conf/ssl/tunnel.your.domain 下:
$ docker run -d --name ngrok-srv \
> -p 5442:80 -p 5443:443 -p 4443:4443 \
> -v /usr/local/nginx/conf/ssl/tunnel.your.domain/certs:/usr/local/ngrok/certs \
> -e NGROK_DOMAIN='tunnel.your.domain' \
> -e TLS_KEY=/usr/local/ngrok/certs/tunnel.your.domain.key \
> -e TLS_CRT=/usr/local/ngrok/certs/fullchain.cer ngrok
複製代碼
本地 ngrok 客戶端鏈接時,你還須要這些配置:
server_addr: tunnel.your.domain:4443
trust_host_root_certs: true
複製代碼
將上面的內容保存爲 ngrok.yml
,你能夠這樣使用它:
$ ngrok -config ngrok.yml -subdomain test 3000
複製代碼
OK 👌,就是這樣,你能夠寫個 express 服務快速測試一下:
const app = require('express')();
app.get('/', (req, res) => {
res.send(`<header style="padding: 40px> <h3>Welcome to ngrok</h3> <small>Introspected tunnels to localhost</small> <img src="https://user-gold-cdn.xitu.io/2019/4/21/16a3eff6610a9d5d?imageView2/2/w/480/h/480/q/85/interlace/1"> </header>`);
});
app.listen(3000);
console.log('Listen on port 3000!');
複製代碼
打開瀏覽器,訪問 https://test.tunnel.you.domain
:
是否是很酸爽? 🥳
ngrok 做爲一項知名開源內網穿透項目而爲人所熟知,然而人家也是要恰飯的嘛,因此 ngrok@2 就閉源了,成爲了一個商業付費項目,不過好在 ngrok@1.x 的源碼還在 github 上能夠找到,因此早 fork 保平安咯~