本文是:SSH Tunnel - Local and Remote Port Forwarding Explained With Examples 的譯文
有兩種方法可以創建SSH隧道,本地和遠程端口轉發(也有動態轉發,但我們不在這里討論)。最好的理解方法是通過一個示例,讓我們從本地端口轉發開始。
本地端口轉發
假設您處於一個不允許連接到特定服務器的專用網絡上。比方說,你在工作,imgur.com被封鎖。為了繞過這個,我們可以通過一台服務器創建一個不在我們的工作網絡的隧道,從而可以訪問Imgur。
$ ssh -L 9000:imgur.com:80 user@example.com
這里的關鍵是-L選項, 告訴我們正在進行本地端口轉發,將端口9000轉發到imgur.com:80, 80是HTTP的默認端口。現在,只需要打開瀏覽器然后訪問:
http://localhost:9000
SSH隧道的好處在於它們是加密的。沒有人會看到你訪問的網站,他們只看到SSH連接到你的服務器。
連接到防火牆后面的數據庫
另一個很好的例子是,如果你需要訪問服務器端口,且只能從本地主機訪問,而不能遠程訪問。
這里的一個例子是當您需要連接到數據庫控制台時,出於安全上的考慮,僅允許本地連接。 假設您在服務器上運行PostgreSQL,默認情況下在端口5432上監聽。
ssh -L 9000:localhost:5432 user@example.com
在這里更改的部分是localhost:5432,它表示將連接從本地端口9000轉發到服務器的5432端口。 現在我們可以直接連接到我們的數據庫。
psql -h localhost -p 9000
現在讓我們在這里停下來一點點解釋實際發生了什么。 在第一個例子中,9000:imgur.com:80實際上是將本地端口9000轉發到imgur.com端口80。您可以想象您的服務器上的SSH實際上是在兩個端口之間建立連接(一個隧道),一個在您的本地機器,一個在目標機上。
但是如果我們說的是9000:localhost:5432,那就意味着從服務器的角度來看localhost,而不是本機上的localhost。 這意味着將本地端口9000轉發到服務器上的端口5432,因為當您在服務器上時,localhost表示服務器本身。[因為這里,ssh登陸到目標機器上]
這可能讓人有點困惑,但重要的是要了解語法實際上意味着什么。
遠程端口轉發
現在是本教程的第二部分,遠程端口轉發。 這最好以一個例子來解釋。
假設您正在本地計算機上開發Rails應用程序,並且希望將其顯示給朋友。 不幸的是,您的ISP沒有為您提供公共IP地址,因此無法通過互聯網直接連接到您的計算機。
有時這可以通過在您的路由器上配置NAT(網絡地址轉換,其實就是在路由器上做內網端口映射,也即端口轉發)來解決,但這並不總是能夠正常工作,並且需要您更改路由器上的配置,這並不總是可取的。 當您的網絡上沒有管理員訪問權限時,此解決方案也不起作用。
要解決這個問題,您需要另一台可以公開訪問並具有SSH訪問權限的計算機。 只要您可以連接到互聯網上,它可以是任何服務器。 我們會告訴SSH在服務器上打開一個新端口的隧道,並將其連接到本機端口。
ssh -R 9000:localhost:3000 user@example.com
這里的語法非常類似於本地端口轉發,將-L變成-R。 但是與本地端口轉發一樣,語法保持不變。
首先,您需要指定遠程服務器將偵聽的端口,在這里為9000,接下來的本地機器的本地端口(在這種情況下為3000)。
還有一件事情你需要做,以實現這一點。 SSH不默認允許遠程主機轉發端口。 要啟用,需要打開配置文件:/etc/ssh/ssh_config,並在配置文件中某個地方添加以下行:
$ sudo vim /etc/ssh/sshd_config
GatewayPorts yes
確保你只添加了一次。重啟SSH服務:
sudo service ssh restart
此后,您應該能夠遠程連接到服務器,甚至可以從本地計算機連接到服務器。 這樣做的方式是您首先創建一個SSH通道,將流量從端口9000上的服務器轉發到端口3000上的本地計算機。這意味着如果您從本地計算機連接到端口9000上的服務器, 實際上通過SSH隧道向您的機器發出請求。
一些小提示
您可能已經注意到,每次創建一個隧道時,您也可以將SSH登錄到服務器並獲得一個shell。 這通常不是必需的,因為您只是想創建一個隧道。 為了避免這種情況,我們可以使用-nNT標志運行SSH,如下所示,這將導致SSH不分配tty,只能做端口轉發。
ssh -nNT -L 9000:imgur.com:80 user@example.com
SSH有很多功能,所以建議您在man ssh上檢查手冊頁面,其中包含更多提示。
【例】映射巡風掃描器到外網
其實我要做的是將內網部署的web服務,通過外網ip能夠訪問,VPS你懂的,又貴,所以不能完全將一個很大的東西放在VPS上...
本想映射烏雲鏡像的,無奈不在本機上...
現在有的是一個內網機器上的巡風掃描系統:http://192.168.1.108/login 一個可SSH登陸的VPS:165.227.29.209
VPS上還搭建了一個DVWA: http://165.227.29.209/dvwa/login.php
現在就想在VPS上做一個遠程端口轉發,通過訪問VPS上的端口就能直接訪問到本地的服務。
Step 1: 登陸配置SSH
starnight:~ starnight$ ssh root@165.227.29.209 root@165.227.29.209's password: [input your login password here]
root@ubuntu-512mb-sfo2-01:~# ifconfig eth0 | grep inet
inet addr:165.227.29.209 Bcast:165.227.31.255 Mask:255.255.240.0
inet6 addr: fe80::5446:75ff:fe13:726e/64 Scope:Link
root@ubuntu-512mb-sfo2-01:~# vim /etc/ssh/sshd_config
在你喜歡的地方加上下面這行, 記住,只能出現一次。
重啟SSH服務:
root@ubuntu-512mb-sfo2-01:~# service ssh restart
Step 2: 遠程端口轉發
在你需要將web服務映射出去的機器上運行如下命令:
root@starnight:~# ifconfig ens33 | grep inet root@starnight:~# ssh -R 8080:localhost:80 root@165.227.29.209
因為VPS上的80端口已經部署了dvwa,現使用8080端口:
Step 3: 訪問測試
訪問遠程VPS的8080端口:http://165.227.29.209:8080/login
這樣就能通過外部ip訪問到本地機器上部署的服務了。
SSH連接不掉線
用SSH進行連接有個小問題就是過段時間之后,ssh連接會斷開,當然服務器不可能讓ssh連接一直保持的。如果想一直保持ssh連接的話,可以參考如下解決方案。
打開服務器 /etc/ssh/sshd_config,我在最后增加一行 ClientAliveInterval 60 ClientAliveCountMax 1
再重啟一下SSH服務器:
service sshd restart
SSH不get shell
一般來講,如果我們只需要進行端口轉發,而不需要拿到一個shell的話,可以設置一個選項:-nNT
$ ssh -nNT -L 9000:imgur.com:80 user@example.com