用ngrok做內網穿透

背景

  • 很多時候,我們都有這樣的需求:需要將本地正在開發的服務暴露在公網上,也就是從外網直接訪問我們本機上的服務。

  • 正常情況下,這是辦不到的,因爲我們的本機並沒有公網 IP,我們的本機處在內網當中。

NAT 穿透原理

這裏需要順手提及一個知識:NAT 穿透。

一個栗子

我們的機器一般都在路由器的內網當中,IP 地址基本上都是192.168.x.x系列,我們並沒有公網 IP,那麼如何訪問外網呢?

  • 我們打開瀏覽器訪問 Google,Google 與我們主機之間如何通信?
    假設我們主機 IP 爲192.168.0.100,路由器 LAN IP 爲192.168.0.1,WAN IP 爲211.22.145.234(這是一個公網 IP),Google 服務器 IP 爲74.125.204.101

  • 詳細通信流程如下:

    • 主機構建 HTTP 請求數據包,目標 IP 爲74.125.204.101,目標端口80/443,源 IP 爲192.168.0.100,源端口隨機生成,假定爲5000
    • 主機檢查目標 IP 地址,發現不在一個網段,數據包丟給默認網關192.168.0.1
    • 路由器 LAN 口收到數據包,構建 NAT 映射,隨機生成端口,假定爲5500,這樣映射就是 :5500 -> 192.168.0.100:5000。WAN 口收到的數據包,如果目標端口是5500,則轉發給內網 IP 爲192.168.0.100的機器的5000端口。
    • 路由器修改數據包的源端口爲5500,源 IP 地址爲211.22.145.234,使用 WAN 口將數據包發送出去。
    • Google 服務器收到請求,構建響應 HTTP 數據包,目標 IP 地址211.22.145.234,目標端口爲5500
    • 路由器 WAN 口收到數據包,目標端口爲5500,查詢 NAT 表,發現對應的機器是192.168.0.100:5000,所以修改目標 IP 爲192.168.0.100,目標端口爲5000。並通過 LAN 口發送給主機。
    • 主機接收到數據包,完成這一次通信。

從上面可以看出,內網機器能夠和外網通信,全靠擁有公網 IP 的路由器做交通樞紐。
路由器通過查詢 NAT 表,來確定數據包該發送給內網哪臺機器。
所以內網多臺機器都可以通過這一臺路由器和外網進行通信。這極大的節省了寶貴的公網 IP 資源。

Ngrok

  • 而 ngrok 就是利用以上原理實現了內網穿透的工具,只是稍有不同,交換的工具從路由器變成了我們具有固定 IP 的 VPS。
    當然原理沒有大變,都是找一個公網服務器做中介。此處成爲服務器 A。流程如下。
1. 本地內網主機和服務器A構建一條連接
2. 用戶訪問服務器A
3. 服務器A聯繫本地內網主機獲取內容
4. 服務器A將獲取到的內容發送給用戶
5. 通過上面的流程,就實現了用戶訪問到了我們內網的內容。
  • 那麼幫助我們實現這個功能的程序就是 Ngrok 。通過在服務器上安裝 Ngrok ,我們就可以和本地主機構建一條隧道。來讓外網用戶訪問本地主機的內容。

準備工作

安裝依賴

  • 注意 golang 需要 1.6 以上,否則不能編譯客戶端
  • 下面是 1.7.3,其他的自己去官網下載,我使用的 Ubuntu 16,自帶的即可
wget https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz
tar -zxvf go1.7.3.linux-amd64.tar.gz -C /usr/local

獲取 ngrok 源碼

git clone https://github.com/inconshreveable/ngrok.git ngrok
## 建議請使用下面的地址,修復了無法訪問的包地址
git clone https://github.com/tutumcloud/ngrok.git ngrok
cd ngrok

生成證書

  • 生成並替換源碼裏默認的證書,注意域名修改爲你自己的
    (之後編譯出來的服務端客戶端會基於這個證書來加密通訊,保證了安全性)
NGROK_DOMAIN="liyuans.com"

openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt

cp base.pem assets/client/tls/ngrokroot.crt

編譯服務端

sudo make release-server
  • 如果一切正常,ngrok/bin 目錄下應該有 ngrok、ngrokd 兩個可執行文件。
    ngrokd 爲服務器端使用的,ngrok 是 linux 客戶端使用的

服務端

  • 前面生成的 ngrokd 就是服務端程序了,指定證書、域名和端口啓動它(證書就是前面生成的,注意修改域名):
sudo ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="liyuans.com" -httpAddr=":8081" -httpsAddr=":8082"
  • 到這一步,ngrok 服務已經跑起來了,可以通過屏幕上顯示的日誌查看更多信息。
  • httpAddr、httpsAddr 分別是 ngrok 用來轉發 http、https 服務的端口,可以隨意指定。
  • ngrokd 還會開一個 4443 端口用來跟客戶端通訊(可通過 -tunnelAddr=":xxx" 指定),如果你配置了 iptables 規則,需要放行這三個端口上的 TCP 協議。

測試連接

  • 現在,通過 http://liyuans.com:8081 和 https://liyuans.com:8082 就可以訪問到 ngrok 提供的轉發服務。
    爲了使用方便,建議把域名泛解析到 VPS 上,這樣能方便地使用不同子域轉發不同的本地服務。

  • 可以看到這樣一行提示:Tunnel liyuans.com:8081 not found,這說明萬事俱備,只差客戶端來連了。

編譯客戶端

#windows
GOOS=windows GOARCH=amd64 make release-client
#mac
GOOS=darwin GOARCH=amd64 make release-client

客戶端

  • 如果要把 linux 上的服務映射出去,客戶端就是前面生成的 ngrok 文件。(在 bin 文件夾內)

  • 寫一個簡單的配置文件,隨意命名如 ngrok.cfg:

server_addr: imququ.com:4443
trust_host_root_certs: false
  • 指定子域、要轉發的協議和端口,以及配置文件,運行客戶端:
./ngrok -subdomain pub -proto=http -config=ngrok.cfg 80
  • 不出意外可以看到這樣的界面,這說明已經成功連上遠端服務了

原文地址:https://liyuans.com/archives.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章