建立稳定安全的SSH隧道
本文將教你如何通過 SSH 隧道把本地服務映射到外網,以方便調試,通常把這種方法叫內網穿透。
目的
把運行在本地開發機上的 SSH 服務(或其他服務如HTTP等)映射到外網,讓全世界都能通過外網 IP 服務到你本地開發機上 的SSH、HTTP 服務。例如你本地的 HTTP 服務監聽在?127.0.0.1:22,你有一臺公網 IP 為?12.34.56.78?的服務器,通過本文介紹的方法,可以讓全世界的用戶通過?http://12.34.56.78:22?訪問到你本地開發機上的 SSH 服務。
前提條件
為了把內網服務映射到外網,以下資源為必須的:
要滿足以上條件很簡單:
- 對于條件1:購買一臺低配 Linux 服務器,推薦國外的?DigitalOcean;
- 對于條件2:對于 Mac、Linux 開發機是內置了 ssh 客戶端的,對于 Windows 可以安裝?Cygwin。
公網IP申請
去網上申請服務器,一般都會收費,如阿里云、騰訊云、百度云等。在這里推薦由世紀互聯運營的微軟Azure云服務器,1元體驗一個月,申請與部署方式很簡單,而且服務器配置與帶寬很高,可惜的是就能使用一個月,其實學服務器開發的大學朋友們也可以申請一個練練手,畢竟這是一次難得的實踐機會嘛!申請免費使用網址如下https://www.azure.cn/pricing/1rmb-trial-full/。
下面這個操作尤為重要,部署成功服務器后,務必參照微軟的文檔為服務器添加入站與出站規則,也就是哪些類型的數據包可以進出你的服務器,那些類型的數據包會被防火墻攔截,這個步驟決定著偽裝的數據包是否能夠進入到我們的VBS。然后我們需要建立linux虛擬機,性能不需要太好,因為她的功能只是一個橋接的作用。虛擬機申請完成后我們就會得到系統自動分配的一個公網IP地址,通過遠程連接軟件我們可以遠程連接到這臺公網的服務器。我們想要作的是將內網中的機器映射到外網,然后我們可以在公網上通過連接這臺服務器連接到我們的這臺內網計算機。最簡單的實現方式就是利用SSH隧道進行端口映射。
實現原理
SSH 隧道就像一根管道,能把任何2臺機器連接在一起,把發送到其中一臺機器的數據通過管道傳輸到另一臺機器。假如已經通過 SSH 隧道把本地開發機和外網服務器連接在了一起,外網服務器端監聽在?12.34.56.78:8080,那么所有發給?12.34.56.78:8080?的數據都會通過 SSH 隧道原封不動地傳輸給本地開發機的?127.0.0.1:8080,如圖所示:
也就是說,去訪問?12.34.56.78:22?就像是訪問本地開發機的?127.0.0.1:22,本地開發機上的 22 端口被映射到了外網服務器上的 22 端口。
如果你的外網服務器 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 2000:127.0.0.1:22 username@12.34.56.78如果想同時映射多個端口則可以執行:
ssh username@12.34.56.78 -R 2000:127.0.0.1:22 -R 8081:127.0.0.1:8081可以看出實現 SSH 隧道的命令相對于 SSH 登入多出來?-R 8080:127.0.0.1:22,多出的這部分的含義是:
在遠程機器(12.34.56.78)上啟動 TCP 8080端口監聽著,再把遠程機器(12.34.56.78)上8080端口映射到本地的127.0.0.1:22。
執行完以上命令后,就可以通過?12.34.56.78:8080?去訪問本地的?127.0.0.1:22?了。
通常把這種技術叫做 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.78OpenSSH基于安全的理由,如果用戶連線到SSH Server后閑置一段時間,SSH Server會在超過特定時間后自動終止SSH連線。
用 ssh 命令連接服務器之后,如果一段時間不操作,再次進入 Terminal 時會有一段時間沒有響應,然后就出現錯誤提示:
Write failed: Broken pipe只能重新用 ssh 命令進行連接。
解決方法
方法一:如果您有多臺服務器,不想在每臺服務器上設置,只需在客戶端的 ~/.ssh/ 文件夾中添加 config 文件,并添加下面的配置:
ServerAliveInterval 60方法二:如果您有多臺個人管理服務器,不想在每個客戶端進行設置,只需在服務器的 /etc/ssh/sshd_config 中添加如下的配置:
ClientAliveInterval 60方法三:如果您只想讓當前的 ssh 保持連接,可以使用以下的命令:
$ ssh -o ServerAliveInterval=60 user@sshserver但是有時候還是會出問題,這個可能就是由于網絡不穩定造成的問題,我們想讓SSH隧道不會調線就需要在網絡不穩定的時候讓他自己去自動連接,重新建立通信隧道。然后時刻保持連接,這個時候AutoSSH這個小軟件就是個不錯的選擇。
通過?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 隧道能實現內網穿透外,還有以下常用方法。
frp
frp 是一個可用于內網穿透的高性能的反向代理應用,支持 tcp, udp, http, https 協議。
frp 有以下特性:
- frp 比 SSH 隧道功能更多,配置項更多;
- frp 也需要一臺外網服務器,并且需要在外網服務器上安裝 frps,在本地開發機上安裝 frpc;
ngrok
ngrok 是一個商用的內網穿透工具,它有以下特點:
- 不需要有外網服務器,因為 ngrok 會為你提供;
- 只需要在本地開發機安裝 ngrok 客戶端,和注冊 ngrok 賬戶;
- 按照服務收費;
這些代替方案的缺點在于都需要再額外安裝其它工具,沒有 SSH 隧道來的直接。
想了解更多可以訪問它們的主頁。
總結
舉兩個例子具體說明一下ssh隧道建立的具體命令參數
ssh的確很強大,可以很方便的實現從本地端口到遠程端口的映射,通常情況下使用 -L 或者 -R參數,例如:
ssh xxx@xxx.xxx -L 8023:RemoteIP:23
-L 將本地的某個端口映射到遠程主機的某個端口上,上例中就是將本地的8023端口映射到遠程主機的23號端口上,這樣就可以直接telnet本機的8023端口來訪問遠程主機了。
但是需要說明的是RemoteIP可以是127.0.0.1,此時127.0.0.1指的是遠程計算機,而非本機地址。
-R 則正好與-L相反,它將遠程主機的某個端口映射到本地的某個端口上,例如:
ssh xxx@xxx.xxx -R 8023:LocalIP:23
上例將遠程主機的8023端口映射到本機的23號端口,這樣遠程主機就可以telnet 自己的8023端口來訪問本地主機了。
最后-D參數將在本地開啟一個socks5代理端口,該端口接收到的數據將通過加密隧道傳輸到遠程主機,并有遠程主機代理發出,例如:
ssh xxx@xxx.xxx -D 7070
上例在本地開啟一個7070號socks5代理,瀏覽器等應用程序可以使用該端口通過遠程主機訪問網絡。
需要說明的是,-D參數開啟的socks代理,在我的機器上好像只有Chrome能使用,IE不能使用,原因未明,估計是DNS解析的問題。
開發中經常需要外網服務映射到本機內網服務的需要,便于調試。
以前都是同事幫著配,這兩天自己也看了一下 ssh 端口轉發。 同事分分鐘鐘搞定的事情,自己折騰了 2 天, 真是弱爆了。
最初老想不明白一件事,為什們外網服務器能夠找到我的內網機器,現在才明白原來走的是 ssh 隧道。
需求我的內網機器 ?192.168.9.100, 我的阿里云外網 123.56.86.52, ?現在需要所有對?123.56.86.52 ?80 端口的訪問都映射到 ?192.168.9.100 的 80 端口。
顯然?123.56.86.52 訪問不到 ?192.168.9.100, 但?192.168.9.100 能訪問到?123.56.86.52 , 所以很簡單 ssh 建立一個遠程端口轉發就行了。
1 ?在?192.168.9.100 上執行
ssh -N -v -R 3000:127.0.0.1:80 root@123.56.86.52-R 表示遠程轉發, ?這句話的意思是 通過 ssh 連接到 123.56.86.52,讓?123.56.86.52 監聽自己的 3000 端口, 所有通過 3000 端口的數據都通過 ssh 轉發到?127.0.0.1 的 80 端口。
這里 127.0.0.1 就是?192.168.9.100 這個機器。 ?在 ?ssh 連接的時候通道就建立了, 以后所有的通信都走的是這個通道。
2 既然??123.56.86.52 已經監聽在 3000 端口了, 接下來就非常簡單了, ?服務器上用 nginx 做一個反向代理, 把 ?80 端口代理到 ?3000 端口就行了
參考文獻
https://github.com/gwuhaolin/blog/issues/11
https://www.cnblogs.com/zlgxzswjy/p/9796671.html
https://www.cnblogs.com/wumz/p/9721666.html
https://blog.csdn.net/u013511989/article/details/79972435
http://www.ha97.com/4070.html
https://www.cnblogs.com/kevingrace/p/6110842.html
?
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的建立稳定安全的SSH隧道的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于fiddler的网络爬虫校园网自动登
- 下一篇: python生成目录树_Python生成