如何通過SSH反向隧道,訪問NAT后面的Linux服務器?
譯文假設你在家里運行一臺Linux服務器,該服務器位于NAT路由器或限制性防火墻后面。現在,你想在不在家的時候,可以通過SSH連接到家用服務器。你該如何做到這一點?SSH端口轉發無疑是一個辦法。然而,如果你面對的是多重嵌套NAT環境,端口轉發會變得很棘手。此外,由于每家ISP的情況不一樣,比如限制性ISP防火墻阻止轉發端口,或者運營商級NAT在諸多用戶之間共享IPv4端口,端口轉發也會受到干擾。
何謂SSH反向隧道?
除了SSH端口轉發外,另一個辦法就是SSH反向隧道。SSH反向隧道這個概念其實很簡單。為此,你需要在限制性家用網絡外面有另一個主機,即所謂的“中繼主機”(relay host),你可以從所在地方通過SSH連接到該主機。你可以使用帶公共IP地址的虛擬專用服務器(VPS)實例來建立中繼主機。然后要做的就是建立一條持久性SSH隧道,從你家用網絡的服務器通向公共中繼主機。有了這條隧道,你就可以從中繼主機“連回”到家用服務器(這就是為什么它叫“反向”隧道)。無論你人在什么地方,或者你家用網絡中的NAT或防火墻限制多嚴格,只要你可以連接到中繼主機,就可以連接到家用服務器。
在Linux上建立SSH反向隧道
不妨看看我們如何可以建立并使用一條SSH反向隧道。我們假設下列設置。我們將建立一條從家用服務器(homeserver)到中繼服務器(relayserver)的SSH反向隧道,那樣我們就可以從另一臺名為clientcomputer的計算機,通過中繼服務器以SSH的方式連接到家用服務器。中繼服務器的公共IP地址是1.1.1.1。
在家用服務器上,打開通向中繼服務器的SSH連接,如下所示。
homeserver~$ ssh -fN -R 10022:localhost:22 relayserver_user@1.1.1.1
這里的端口10022是你可以選擇的任何隨意的端口號。只要確保該端口沒有被中繼服務器上的其他程序所使用就行。
“-R 10022:localhost:22”選項定義了反向隧道。它通過中繼服務器的端口1022,將流量轉發到家用服務器的端口22。
若使用“-fN”選項,一旦你成功驗證了身份、登錄到SSH服務器,SSH就會徑直進入后臺。如果你不想在遠程SSH服務器上執行任何命令,只想轉發端口,就像在本文的示例中,這個選項很有用。
運行上述命令后,你將直接回到家用服務器的命令提示符。
登錄進入到中繼服務器,核實127.0.0.1:10022綁定到sshd。如果是這樣,那意味著反向隧道已正確建立起來。
relayserver~$ sudo netstat -nap | grep 10022 tcp 0 0 127.0.0.1:10022 0.0.0.0:* LISTEN 8493/sshd
現在可以從其他任何計算機(比如clientcomputer),登錄進入到中繼服務器。然后訪問家用服務器,如下所示。
relayserver~$ ssh -p 10022 homeserver_user@localhost
需要注意的一個地方就是,你為localhost輸入的SSH登錄信息/密碼應該適用于家用服務器,而不是適用于中繼服務器,因為你是通過隧道的本地端點登錄進入到家用服務器。所以別為中繼服務器輸入登錄信息/密碼。成功登錄后,你就接入到了家用服務器。
通過SSH反向隧道,直接連接到NAT后面的服務器
雖然上述方法讓你可以連接到NAT后面的家用服務器,但是你需要登錄兩次,先登錄到中繼服務器,然后登錄到家用服務器。這是由于中繼服務器上SSH隧道的端點綁定到回送地址(127.0.0.1)。
但實際上,只要單次登錄到中繼服務器,就可以直接連接到NAT后面的家用服務器。為此,你需要讓中繼服務器上的sshd不僅可以從回送地址轉發端口,還可以從外部主機轉發端口。這可以通過在中繼服務器上運行的sshd里面指定GatewayPorts選項來實現。
打開中繼服務器的/etc/ssh/sshd_conf,添加下面這一行。
relayserver~$ vi /etc/ssh/sshd_conf GatewayPorts clientspecified
重啟sshd。
基于Debian的系統:
relayserver~$ sudo /etc/init.d/ssh restart
基于紅帽的系統:
relayserver~$ sudo systemctl restart sshd
現在不妨從家用服務器開始建立SSH反向隧道,如下所示。
homeserver~$ ssh -fN -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1
登錄進入到中繼服務器,用netstat命令核實SSH反向隧道已成功建立起來。
relayserver~$ sudo netstat -nap | grep 10022 tcp 0 0 1.1.1.1:10022 0.0.0.0:* LISTEN 1538/sshd: dev
不像之前的情況,隧道的端點現在是1.1.1.1:10022(中繼服務器的公共IP地址),而不是127.0.0.1:10022。這意味著,可以從外部主機連接到隧道端點。
現在可以從其他任何計算機(比如clientcomputer),輸入下列命令,訪問NAT后面的家用服務器。
clientcomputer~$ ssh -p 10022 homeserver_user@1.1.1.1
在上述命令中,雖然1.1.1.1是中繼服務器的公共IP地址,但homeserver_user必須是與家用服務器關聯的用戶帳戶。這是由于,你實際登錄進入的主機是家用服務器,而不是中繼服務器。后者只是將你的SSH流量中繼轉發到家用服務器而已。#p#
在Linux上建立持久性SSH反向隧道
想必你已明白了如何建立一條SSH反向隧道,現在不妨讓隧道具有“持久性”,那樣隧道隨時建立并運行起來(無論面對什么樣的情況:暫時網絡擁塞、SSH超時還是中繼主機重啟等)。畢竟,要是隧道沒有始終建立起來,你也就無法可靠地連接到家用服務器。
為了建立持久性隧道,我要使用一款名為autossh的工具。顧名思義,萬一SSH會話由于任何原因而斷開,這個程序讓你可以自動重啟SSH會話。所以,讓SSH反向隧道保持持久連接很有用。
第一步,不妨建立無需密碼的SSH登錄機制,從家用服務器登錄到中繼服務器。那樣一來,autossh就能重啟斷開的SSH反向隧道,不需要用戶干預。
下一步,將autossh安裝到發起隧道的家用服務器上。
從家用服務器運行帶下列變量的autossh,從而建立一條通向中繼服務器的持久性SSH隧道。
homeserver~$ autossh -M 10900 -fN -o "PubkeyAuthentication=yes" -o "StrictHostKeyChecking=false" -o "PasswordAuthentication=no" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1
“-M 10900”選項指定了中繼服務器上的一個監控端口,將用來交換測試數據,以監控SSH會話。該端口不應該被中繼服務器上的任何程序所使用。
“-fN”選項傳遞給ssh命令,讓SSH隧道可以在后臺運行。
“-o XXXX”選項指令ssh執行下列操作:
•使用密鑰驗證,而不是密碼驗證。
•自動接受(未知的)SSH主機密鑰。
•每60秒就交換持久連接(keep-alive)消息。
•最多發送3個持久連接消息,而不接受任何響應。
與SSH反向隧道有關的其余選項仍與之前一樣。
如果你希望SSH隧道一啟動就自動建立起來,可以在/etc/rc.local中添加上述的autossh命令。
結束語
我在本文中介紹了如何可以使用SSH反向隧道,從外面訪問限制性防火墻或NAT網關后面的Linux服務器。我演示的使用場合是通過公共VPS訪問家用網絡,可是你在用于企業網絡時需要小心。可以認為這類隧道違反了企業政策,因為它避開了企業防火墻,因而將企業網絡暴露在外部攻擊者面前。它被誤用或濫用的可能性很大。所以,在建立SSH反向隧道之前總是要牢記因此帶來的影響或后果。
英文:How to access a Linux server behind NAT via reverse SSH tunnel