1 ssh 端口轉發
ssh(Secure Shell)是一種網絡傳輸協議,它能夠在客戶端和服務器之間創建安全的隧道連接。最常見的功能就是遠程登錄,這不是本文的重點,不過也會涉及到密鑰登錄(避免輸入密碼)。本文將使用ssh做端口轉發,ssh端口轉發有三種模式:
- 本地端口轉發(Local Port Forwarding)
- 遠程端口轉發(Remote Port Forwarding)
- 動態端口轉發(Dynamic Port Forwarding)
1.1 本地端口轉發
本地主機登錄服務器后,將本地主機指定的端口映射到服務器指定的端口,從而實現用戶在訪問本地主機時,就等于訪問服務器的效果。例如:服務器上有一個web站點訪問地址是http://192.168.0.3:5000 ,服務器防火墻上并沒有開啟5000端口,如果直接輸入網址,是訪問不到該web站點的。這時可以利用本地端口轉發功能,將請求本地主機的4000端口的數據轉發到服務器上的5000端口上,具體做法如下:
ssh -fNL 4000:192.168.0.3:5000 root@192.168.0.3
上面命令的中
-f
選項表示本地主機的ssh客戶端在后臺運行-N
選項表示不執行遠程命令,只用于轉發端口,及本地主機在登錄了192.168.0.3后,不會分配一個tty窗口。-
-L
選項表示這是一個本地轉發模式,它的參數是 port:host:hostport,對應到這里是4000:192.168.0.3:5000port
參數表示本地主機的端口,及要通過該端口轉發數據到目標主機host:hostport
參數表示經過遠程服務器(及使用ssh登錄的服務器ssh root@192.168.0.3)轉發的目標主機和端口。在這個例子中,目標主機和遠程服務器都是192.168.0.3。既然他們是一臺主機,那么也可以用下面的命令來代替:-
ssh -fNL 4000:localhost:5000 root@192.168.0.3 # 或者 ssh -fNL 4000:127.0.0.1:5000 root@192.168.0.3
上面的localhost和127.0.0.1是相對于通過ssh登錄的遠程服務器的。
root@192.168.0.3
是ssh的登錄命令,只有登錄了遠程服務器后,才能執行端口轉發
執行完上面的命令后,可以在本地主機的瀏覽器上輸入http://localhost:4000 訪問遠程服務器192.168.0.3:5000上的web站點。
現在,假如有另外一臺服務器10.1.1.10,上面部署了一個web應用(地址為http://10.1.1.10 ,端口為80),本地主機不能直接訪問該站點的web服務器,而192.168.0.3上能夠訪問得到這臺服務器。根據上面的知識,我們知道,10.1.1.10:80是我們的目標主機和端口,192.168.0.3作為遠程服務器,與我們本地主機和目標主機的網絡都是連通的,我們就可以通過以下命令將本地主機的4000端口的數據轉發到目標主機(10.1.1.10)的80端口上。
ssh -fNL 4000:10.1.1.10:80 root@192.168.0.3
此時,我們輸入http://localhost:4000,就能訪問到http://10.1.1.10站點的內容
1.2 遠程端口轉發
遠程端口轉發是將遠程服務器端口映射到本地端口,方便其他不能直接訪問本地網絡的主機訪問。比如,家里的電腦要訪問公司內部服務器(192.168.0.5)上的web站點(部署在80端口上),因為它們是不能直接通信的,所以需要有一臺遠程服務器(比如:123.123.123.123)作端口轉發。
此時,我們需要在遠程服務器上開一個端口,這里假設為8000端口,將8000端口與內部服務器上的80端口做綁定,然后我們在家里只需要訪問遠程服務器的8000端口,即可與訪問到內部服務器的web站點。具體做法是,在內部服務器192.168.0.5上執行如下指令:
ssh -fNR 8000:localhost:80 root@123.123.123.123
在上面的命令中:
-
-R
選項代表的是遠程端口轉發模式,它的參數是port:host:hostport,對應這里的是8000:localhost:80-
port
與-L
參數中的port不同,-L參數中port代表的是本地的端口,而這里的port代表的是遠程服務器123.123.123.123的端口。 -
host:hostport
參數表示要綁定的本地端口,這里的localhost代表的我們操作的內部服務器,即192.168.0.5,也可以變為127.0.0.1或192.168.0.5。可以是這臺內部服務器能訪問的任何其他服務器資源,這里就不在贅述。
-
執行完上面的命令后,我們在家里通過輸入http://123.123.123.123:8000,即可訪問內部服務器上http://192.168.0.5 的站點。
1.3 動態端口轉發
當目標主機不定時,我們就需要使用動態端口轉發。比如,公司內部只有一臺服務器192.168.0.3能夠訪問外網,現在我們需要到網上去查詢一些資料,這些資料的來至不同的服務器,也就是我們的目標地址是不固定的,那么我們就需要這臺服務器192.168.0.3為我們做動態端口轉發。具體指令如下:
ssh -fND 8000 root@192.168.0.3
-
-D
參數表示使用動態端口轉發模式,8000表示本地主機要綁定的端口。當本地主機登錄遠程服務器后,8000端口所收到的數據將會轉發到服務器192.168.0.3上,再由這臺服務器為我們動態的轉發到目標地址。
比如,我們要訪問百度,我們需要將瀏覽器發出的請求先轉發到localhost:8000端口上,由8000端口將數據傳輸到服務器192.168.0.3上,再由服務器動態的將請求轉發至百度服務器上,及實現了本地主機上網查找資料的目的。這里后面的兩步都已經完成,只需要將第一步在本地主機上把瀏覽器的請求轉發到本地的8000端口上。我們可以使用瀏覽器的socks代理,將其請求發送到本地端口即可。
2 使用autossh自動維護連接
不論使用哪種模式,SSH做端口轉發時,都需要在本地主機和遠程服務器之間建立連接(隧道)。這種連接是不穩定的,當網絡情況不好時,連接可能會中斷。autossh可以解決這種問題,它會在本地主機和遠程服務器上做連接檢查(發送測試數據到指定端口),如果發現連接中斷后,會自動重連。
上面的描述中,有兩個問題需要解決
- 在什么端口做連通性檢測
- 如何重連
2.1 使用密鑰登錄服務器
使用ssh連接服務器時,使用用戶名密碼登錄,每次都要輸入密碼。如果是自動重連,我們就需要免密登錄服務器。這里我們要解決的是ssh連接遠程服務器時需要輸入用戶名密碼的問題。ssh除了用戶名密碼登錄外,還有一種登錄方式是使用密鑰登錄,大致過程如下:
我們在本地主機上生成一個密鑰對,將公鑰放在遠程服務器中,私鑰保存在本地主機上,當使用密鑰登錄遠程服務器時,流程如下:
- 客戶端發起連接請求,并將公鑰發送至服務器
- 服務器比對客戶端發送的公鑰是否與本地的公鑰相同,如相同則用公鑰加密一個隨機字符,發送給客戶端,這個認證機制叫challenge/response(質疑-應答認證)
- 客戶端在收到challenge后,使用私鑰解密,并將結果回傳給服務器
- 服務器驗證客戶端回傳的數據后,建立ssh連接
生成密鑰
使用ssh-keygen
生成密鑰對,ssh-keygen有很多參數選項,下面列出我用到的:
- -t 表示生成密鑰的類型,有dsa,rsa等,一般用rsa加密算法
- -C 后面跟附加信息,一般我是跟的個人的名字
ssh-keygen -t rsa -C zebra
這里在輸入私鑰密碼時,選擇為空,為后續autossh自動重連提供方便。生成完后,默認會在用戶家目錄的.ssh目錄下生成id_rsa和id_rsa.pub兩個文件。id_rsa為私鑰文件,id_rsa.pub為公鑰文件,可以看到id_rsa.pub公鑰文件的最后有我們-C選項的附加信息zebra,這樣我們將公鑰上傳至服務器后,能夠很方便的找到自己的公鑰。
上傳公鑰
使用ssh-copy-id
上傳公鑰文件
ssh-copy-id -i root@123.123.123.123
在ssh-copy-id命令中,-i選項后面跟公鑰文件的路徑,如果不加參數,默認是找~/.ssh/id_rsa.pub公鑰文件,我們使用的默認公鑰文件,root@123.123.123.123是指要將公鑰數據存放在遠程服務器的root用戶下,注意:端口轉發必須是連接root用戶。執行完上面的命令后,會在root家目錄下的.ssh目錄中,生成authorized_keys文件,里面保存做上傳的公鑰內容。
2.2 使用autossh維護連接
在客戶端使用命令yum install autossh
安裝autossh,autossh在ssh的基礎上新增加一個參數-M
來檢查隧道的連通性,原理是這樣的,autossh會在-M指定的端口上發送測試數據,并在這個端口+1的端口上接收回響數據。比如:我們設置-M 20000,autossh 會在20000端口上發送測試數據,并在20001端口上接收回傳數據。
舉例說明,我要執行遠程端口轉發的功能,將本地80端口映射到遠程服務器的8000端口,使用ssh命令如下:
ssh -fNR 8000:localhost:80 root@123.123.123.123
如果使用autossh可執行這個命令
autossh -M 20000 -fNR 8000:localhost:80 root@123.123.123.123
autossh會在20000和20001端口上檢查本地客戶端和遠程服務器的連通性,如果發現隧道斷開了,會在執行自動連接,因為我們使用了密鑰登錄,且沒有設置密鑰的密碼,所以就會達到自動重連的效果。