標籤:

調試利器-SSH隧道

在開發微信公眾號或小程序的時候,由於微信平台規則的限制,部分介面需要通過線上域名才能正常訪問。但我們一般都會在本地開發,因為這能快速的看到源碼修改後的運行結果。但當涉及到需要調用微信介面時,由於不和你在同一個區域網中的用戶是無法訪問你的本地開發機的,就必須把修改後的代碼重新發布到線上域名所在的伺服器才能去驗證結果。每次修改都重新發布很繁瑣也很浪費時間。

本文將教你如何通過 SSH 隧道把本地服務映射到外網,以方便調試,通常把這種方法叫內網穿透。

閱讀完本文後,你能解決以下常見問題:

  • 開發微信公眾號等應用時把本地服務映射到外網,加速調試流程;
  • 把你正在開發的本地服務分享給互聯網上其它人訪問體驗;
  • 在任何地方通過互聯網控制你家中在區域網里的電腦;

最終目的

把運行在本地開發機上的 HTTP 服務映射到外網,讓全世界都能通過外網 IP 服務到你本地開發機上的 HTTP 服務。例如你本地的 HTTP 服務監聽在 127.0.0.1:8080,你有一台公網 IP 為 12.34.56.78 的伺服器,通過本文介紹的方法,可以讓全世界的用戶通過 http://12.34.56.78:8080 訪問到你本地開發機上的 HTTP 服務。

總結成一句話就是:把內網埠映射到外網。

前提條件

為了把內網服務映射到外網,以下資源為必須的:

  1. 一台有外網 IP 的伺服器;
  2. 能在本地開發機上通過 ssh 登入到外網伺服器。

要滿足以上條件很簡單:

  • 對於條件1:購買一台低配 Linux 伺服器,推薦國外的 DigitalOcean;
  • 對於條件2:對於 Mac、Linux 開發機是內置了 ssh 客戶端的,對於 Windows 可以安裝 Cygwin。

實現原理

要實現把內網埠映射到外網,最簡單的方式就是通過 SSH 隧道。

SSH 隧道就像一根管道,能把任何2台機器連接在一起,把發送到其中一台機器的數據通過管道傳輸到另一台機器。假如已經通過 SSH 隧道把本地開發機和外網伺服器連接在了一起,外網伺服器端監聽在 12.34.56.78:8080,那麼所有發給 12.34.56.78:8080 的數據都會通過 SSH 隧道原封不動地傳輸給本地開發機的 127.0.0.1:8080,如圖所示:

也就是說,去訪問 12.34.56.78:8080 就像是訪問本地開發機的 127.0.0.1:8080,本地開發機上的 8080 埠被映射到了外網伺服器上的 8080 埠。

如果你的外網伺服器 IP 配置了域名解析,例如 yourdomin.com 會通過 DNS 解析為 12.34.56.78,那麼也可以通過 yourdomin.com:8080 去訪問本地開發機上的服務。

這樣就做到了訪問外網地址時其實是本地服務返回的結果。

通過 SSH 隧道傳輸數據時,數據會被加密,就算中間被劫持,黑客也無法得到數據的原內容。

所以 SSH 隧道還有一個功能就是保證數據傳輸的安全性。

實現步驟

把本地開機和外網伺服器通過 SSH 隧道連接起來就和在本地開發機 SSH 登入遠程登入到外網伺服器一樣簡單。

先來回顧以下 SSH 遠程登入命令,假如想在本地遠程登入到 12.34.56.78,可以在本地開發機上執行以下命令:

ssh username@12.34.56.78

而實現 SSH 隧道只需在本地開發機上執行:

ssh -R 8080:127.0.0.1:8080 username@12.34.56.78

可以看出實現 SSH 隧道的命令相對於 SSH 登入多出來 -R 8080:127.0.0.1:8080,多出的這部分的含義是:

在遠程機器(12.34.56.78)上啟動 TCP 8080埠監聽著,再把遠程機器(12.34.56.78)上8080埠映射到本地的127.0.0.1:8080

執行完以上命令後,就可以通過 12.34.56.78:8080 去訪問本地的 127.0.0.1:8080 了。

通常把這種技術叫做 SSH 遠程埠轉發(remote forwarding)。

其實不限於只能把本地開發機上運行的服務映射到外網伺服器上去,還可以把任何本地開發機可以訪問的服務映射到外網伺服器上去。例如在本地開發機上能訪問 github.com:80,在本地開發機上執行:

ssh -R 8080:github.com:80 username@12.34.56.78

就能通過 12.34.56.78:8080 去訪問 github.com:80 了。

保持運行

在執行完上面介紹的 SSH 隧道命令後,你會發現登入到了外網伺服器上去了,如果你登出外網伺服器,就會發現 12.34.56.78:8080 無法訪問了。導致這個問題的原因是你登出外網伺服器時,在外網伺服器上本次操作對應的 SSH 進程也跟著退出了,而這個退出的進程曾負責監聽在 8080 埠進行轉發操作。

為了讓 SSH 隧道一直保持在後台執行,有以下方法。

通過 SSH 自帶的參數

SSH 還支持這些參數:

  • N參數:表示只連接遠程主機,不打開遠程shell;
  • T參數:表示不為這個連接分配TTY;
  • f參數:表示連接成功後,轉入後台運行;

因此要讓 SSH 隧道一直保持在後台執行,可以通過以下命令:

ssh -NTf -R 8080:127.0.0.1:8080 username@12.34.56.78

通過 AutoSSH

SSH 隧道是不穩定的,在網路惡劣的情況下可能隨時斷開。如果斷開就需要手動去本地開發機再次向外網伺服器發起連接。

AutoSSH 能讓 SSH 隧道一直保持執行,他會啟動一個 SSH 進程,並監控該進程的健康狀況;當 SSH 進程崩潰或停止通信時,AutoSSH 將重啟動 SSH 進程。

使用AutoSSH 只需在本地開發機上安裝 AutoSSH ,方法如下:

  • Mac 系統:brew install autossh
  • Linux 系統:apt-get install autossh

安裝成功後,在本地開發機上執行:

autossh -N -R 8080:127.0.0.1:8080 username@12.34.56.78

就能完成和上面一樣的效果,但本方法能保持 SSH 隧道一直運行。

可以看出這行命令和上面的區別在於把 ssh 換成了 autossh,並且少了 -f 參數,原因是 autossh 默認會轉入後台運行。

常見問題

如果你遇到通過以上方法成功啟動 SSH 隧道後,還是無法訪問 12.34.56.78:8080,那麼很有可能是外網伺服器上的 SSH 沒有配置對。為此你需要去外網伺服器上修改 /etc/ssh/sshd_config 文件如下:

GatewayPorts yes

這個選項的意思是,SSH 隧道監聽的服務的 IP 是對外開放的 0.0.0.0,而不是只對本機的 127.0.0.1。不開 GatewayPorts 的後果是不能通過 12.34.56.78:8080 訪問,只能在外網伺服器上通過 127.0.0.1:8080服務到本地開發機的服務。

修改好配置文件後,你還需要重啟 sshd 服務來載入新的配置,命令如下:

service sshd restart

如果使用以上方法還是無法訪問 12.34.56.78:8080,請檢查你外網伺服器的防火牆配置,確保 8080 埠是對外開放的。

其它代替方案

除了 SSH 隧道能實現內網穿透外,還有以下常用方法。

frp

frp 是一個可用於內網穿透的高性能的反向代理應用,支持 tcp, udp, http, https 協議。

frp 有以下特性:

  • frp 比 SSH 隧道功能更多,配置項更多;
  • frp 也需要一台外網伺服器,並且需要在外網伺服器上安裝 frps,在本地開發機上安裝 frpc;

ngrok

ngrok 是一個商用的內網穿透工具,它有以下特點:

  • 不需要有外網伺服器,因為 ngrok 會為你提供;
  • 只需要在本地開發機安裝 ngrok 客戶端,和註冊 ngrok 賬戶;
  • 按照服務收費;

這些代替方案的缺點在於都需要再額外安裝其它工具,沒有 SSH 隧道來的直接。

想了解更多可以訪問它們的主頁。

閱讀原文

推薦閱讀:

ReactNative 知識小集(1)-深入理解 React Native Debugging
深入X64架構(翻譯轉載)(4)之參數獲取

TAG:軟體調試 |