這裡介紹在 Linux 系統上的 ssh 安全加密連線指令的使用方式與範例,以及相關設定檔的配置技巧。

SSH 是一種安全加密傳輸協定,絕大部分的 Linux 伺服器都會提供 SSH 的連線服務,讓使用者或管理者遠端連線進來,透過 Linux 的 shell 來處理各種工作或系統管理。


以下我們會介紹各種常見的 ssh 指令使用方式,並提供多實用的指令稿範例,讓初學者快速上手,熟悉 Linux 遠端操作與管理的各項技巧。

基本用法

在 Linux 系統上若要使用 SSH 連線至遠端的另外一台 Linux 伺服器,可以使用 ssh 這個指令,其語法為:

ssh 帳號@主機

這裡的「主機」就是遠端主機的 IP 位址或主機名稱,而「帳號」就是那一台遠端主機上的帳號名稱。

舉例來說,如果要以 seal 這個帳號登入 myhost.gtwang.org 這台主機,就執行:

# 連線至 myhost.gtwang.org,以 seal 這個帳號登入(本地端執行指令)
ssh seal@myhost.gtwang.org

建立連線時,要輸入該帳號的密碼,通過認證之後,就可以登入該主機,遠端進行操作。

SSH 預設會以密碼進行認證,若不想輸入密碼,可以改用公開金鑰認證,更方便也更安全,詳細教學請參考 SSH 公開金鑰認證設定教學

主機的指定也可以使用 IP 位址,例如:

# 連線至 192.168.1.2,以 seal 這個帳號登入(本地端執行指令)
ssh seal@192.168.1.2

如果本地端的目前的使用者帳號名稱剛好跟遠端的使用者帳號名稱相同的話,就可以把帳號與 @ 都省略,只指定主機即可,比方說如果本地端的目前的使用者名稱也是 seal 的話,我們就可以省略帳號,只寫主機:

# 連線至 myhost.gtwang.org,以目前正在使用的帳號名稱登入(本地端執行指令)
ssh myhost.gtwang.org

指定連接埠號

標準的 SSH 服務會使用 22 連接埠,但這不是強制性的,許多伺服器會因為安全性因素,改用其他的連接埠,若遇到使用非正規連接埠號的伺服器,我們可以使用 -p 指定埠號,例如指定埠號為 2222

# 指定連接埠號為 2222(本地端執行指令)
ssh -p 2222 seal@myhost.gtwang.org

指端執行指令

若連線到遠端的 Linux 伺服器上,只是為了執行單一指令的話,可以直接把要執行的遠端指令放在 ssh 參數的最尾端,這樣在 SSH 連線建立之後,就會自動執行該指令,執行完成後自動離開,可讓指令更簡潔。

以下的範例會連線至遠端 Linux 伺服器,執行 ls -l 輸出自己目錄下的所有檔案:

# 執行遠端的 ls -l 指令(本地端執行指令)
ssh seal@myhost.gtwang.org ls -l

如果要執行的遠端指令結構比較複雜時,建議使用引號把遠端的指令明確區隔開來,避免 shell 的解析結果跟設計者所想像的情境有所差異。例如若要把遠端 ls -l 的輸出訊息儲存至遠端的 ls.remote.out 檔案中,可以這樣寫:

# 執行遠端的 ls -l 指令,
# 輸出至遠端的 ls.remote.out 檔案(本地端執行指令)
ssh seal@sim.nchc.org.tw 'ls -l > ls.remote.out'

若想要把遠端 ls -l 的輸出訊息儲存至本地端的 ls.local.out 檔案中,則必須這樣寫:

# 執行遠端的 ls -l 指令,
# 輸出至本地端的 ls.local.out 檔案(本地端執行指令)
ssh seal@sim.nchc.org.tw 'ls -l' > ls.local.out

# 或是不加引號亦可(本地端執行指令)
ssh seal@sim.nchc.org.tw ls -l > ls.local.out

在這種有管線導向的指令結構下,引號的使用是很重要的,如果沒有注意的話,執行結果就會跟自己的想像有所落差。

遠端 X Window 顯示

如果想要在遠端 Linux 伺服器上執行圖形介面的程式,將畫面顯示在本地端的螢幕上,可以使用 ssh 的 X11 forwarding 功能,例如:

# 建立支援 X11 forwarding 的 SSH 連線(本地端執行指令)
ssh -X seal@myhost.gtwang.org

在建立支援 X11 forwarding 的 SSH 連線,連線到遠端的 Linux 伺服器上之後,此時只要執行一般的圖形介面程式,就會將視窗畫面直接顯示於本地端的螢幕上了。

# 執行遠端的 xterm(遠端執行指令)
xterm

執行後的畫面會類似這樣,使用起來就跟在本地端執行差不多,只是多少會有一些網路的延遲。

遠端執行 xterm

我們也可以把要執行的指令直接放在 ssh 參數中,簡化成一行指令,這樣的執行效果跟上面的兩行指令相同:

# 建立支援 X11 forwarding 的 SSH 連線,
# 並執行遠端的 xterm(本地端執行指令)
ssh -X seal@myhost.gtwang.org xterm

當我們使用 ssh-X 參數建立支援 X11 forwarding 的 SSH 連線時,遠端的 Linux 伺服器會被視為「不安全、不被信任」的主機,為了保護本地端的系統安全,在這種狀況下某些比較不安全的會被禁止執行,若剛好我們使用的軟體需要執行這些危險動作的話,就會產生錯誤。

若想要將遠端的系統視為「安全且被信任」的主機,可以改用 -Y 參數,其效果跟 -X 類似,只不過不會有任何安全性的限制:

# 建立支援 X11 forwarding 的 SSH 連線,
# 並將遠端 Linux 視為安全且被信任的主機(本地端執行指令)
ssh -Y seal@myhost.gtwang.org

安全加密通道

安全加密通道(SSH tunnel)是建立在 SSH 連線之上的連線通道,任何不具備加密功能的網路連線軟體,只要透過這個通道建立連線,即可受到 SSH 加密連線的保護,避免傳輸的資料被輕易側錄與竊取。

ssh 可以建立的安全加密通道類型總共有四種,第一種是從本地端連線至遠端主機:

# 讓本地端 1234 連接埠連接至 myhost.gtwang.org 主機
# 的 localhost:5678 連接埠
ssh -NL 1234:localhost:5678 myhost.gtwang.org

第二種是從本地端連線至遠端主機後方的另外一台主機:

# 讓本地端 1234 連接埠連接至 myhost2.gtwang.org 主機
# 的 5678 連接埠
ssh -NL 1234:myhost2.gtwang.org:5678 myhost.gtwang.org

第三種是從遠端連線至本地端:

# 讓 myhost.gtwang.org 主機的 1234 連接埠連接至
# 本地端的 localhost:5678 連接埠
ssh -NR 1234:localhost:5678 myhost.gtwang.org

最後一種則是從遠端連線至本地端內部的另外一台主機:

# 讓 myhost.gtwang.org 主機的 1234 連接埠連接至
# 本地端內部主機的 internalhost 的 5678 連接埠
ssh -NR 1234:internalhost:5678 myhost.gtwang.org

關於安全加密通道更詳細的用法與範例,我未來會再寫一篇文章專門介紹,目前請大家先上 Google 查詢「ssh tunnel」這個關鍵字。

背景執行

在使用 ssh 執行某些會持續很久的指令時,在指令執行後 shell 就擋住(等待 ssh 執行完畢),無法繼續執行其他指令,當然我們可以另外再開一個新的終端機來使用,不過這樣可能會讓整個桌面都充斥著停住的終端機。

在執行這類的 ssh 指令時,我們可以加上 -f 參數,讓指令放在背景執行,這樣會造成需要開啟很多終端機的問題,以下是一些常見的使用情境。

最常見的就是執行遠端的圖形介面軟體,通常啟動軟體之後,終端機就會被擋住,加入 -f 參數即可讓 ssh 的指令放在背景執行,而等到我們關閉圖形介面的軟體時,該 ssh 連線就會自動中止,這樣使用起來會更方便:

# 讓 ssh 在背景執行,啟動 xterm
ssh -fX seal@myhost.gtwang.org xterm

另外一個例子就是建立 SSH 安全加密通道,通道建立之後,放在背景執行也會比較方便:

# 讓 ssh 在背景執行,建立安全加密通道
ssh -fNL 1234:localhost:5678 myhost.gtwang.org

除錯模式

開啟 SSH 的除錯模式後,可以輸出詳細的偵錯訊息,協助管理者解決連線問題。

# 開啟第一級除錯模式
ssh -v seal@myhost.gtwang.org

# 開啟第二級除錯模式
ssh -vv seal@myhost.gtwang.org

# 開啟第三級除錯模式
ssh -vvv seal@myhost.gtwang.org

除錯模式下所輸出的訊息會類似這樣:

除錯模式訊息

實用指令稿範例

以下是一些跟 ssh 有關的實用指令稿範例。

遠端複製與備份檔案

若需要在 Linux 伺服器之間複製或備份檔案,可以使用 rsync 這個指令,它預設就會自動使用 ssh 建立安全加密的連線來進行備份:

# 用 rsync 透過 ssh 連線備份檔案
rsync -avzh /mypath/myfile.gz seal@192.168.1.2:/mybackup/

關於更詳細的 rsync 指令用法,請參考 rsync 遠端檔案同步與備份工具教學與範例

除了 rsync 之外,也可以自己使用 ssh 配合 tar 指令,進行檔案的遠端複製或備份:

# 將本地端的 folder 目錄備份至遠端的 /dest/ 目錄下
tar cf - folder | ssh seal@192.168.1.2 "(cd /dest/; tar xf -)"

# 將遠端的 /your/folder 目錄備份至本地端目前目錄下
ssh seal@192.168.1.2 "(cd /your/; tar cf - folder)" | tar xf -

以上的範例只是使用 tar 打包檔案,並使用 ssh 傳送資料,然後直接解開,並沒有壓縮資料,若想要壓縮資料節省網路頻寬,可以在 tar 的參數加上 -c(gzip)或是 -j(bzip2)等壓縮參數。

以下是將檔案壓縮備份的範例:

# 將端的 /your/path/ 目錄備份至本地端的 /my/file.tar.gz
ssh seal@192.168.1.2 tar zcf - /your/path/ > /your/file.tar.gz

# 將本地端的 /my/path/ 目錄備份至遠端的 /your/file.tar.gz
tar zcf - /my/path/ | ssh seal@192.168.1.2 "cat > /your/file.tar.gz"

以下是解壓縮檔案的範例:

# 將本地端的 /my/file.tar.gz 壓縮檔解開,放至於遠端的 /dest/ 之下
ssh seal@192.168.1.2 "(cd /dest/;tar zxf -)" < /my/file.tar.gz

# 將遠端的 /your/file.tar.gz 壓縮檔解開,放至於本地端目前目錄
ssh seal@192.168.1.2 "cat /your/file.tar.gz" | tar zxf -

控制多台 Linux 伺服器

如果想要一次控制多台 Linux 伺服器,執行相同的指令,可以在設定好 SSH 公開金鑰認證之後,使用簡單的 shell 指令稿即可同時對多台 Linux 伺服器送出相同的指令,同時管理多台主機:

#!/usr/bin/bash
# 以迴圈自動對 10 台 Linux 伺服器送出指令
for host in 192.168.1.{20..29}; do
  # 在每一台 Linux 伺服器上執行 hostname 指令
  ssh $host hostname
done

常見問題

以下我整理了一些關於 ssh 指令在使用上常見的問題,以及解決方法。

主機金鑰變更問題

每台開啟 SSH 服務的 Linux 主機,都會自己產生一組獨一無二的主機金鑰,ssh 在連線時都會去核對自己紀錄中的主機金鑰與收到的主機金鑰是否吻合。

當我們的 Linux 伺服器進行一些系統變更時(例如重灌系統),就有可能會改變伺服器上的主機金鑰,隨後 ssh 在檢查主機金鑰時就會發現金鑰不對,而出現這樣的警告訊息:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:Llaul7Wqs6bo2H1YTvNpEmRSAozuIRJCsFuDqBt64lk.
Please contact your system administrator.
Add correct host key in /home/seal/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/seal/.ssh/known_hosts:1
ECDSA host key for dendrite02 has changed and you have requested strict checking.
Host key verification failed.

遇到這種狀況時,可將 ~/.ssh/known_hosts 這個主機金鑰紀錄刪除,讓 ssh 自動重新抓取新的主機金鑰即可:

rm ~/.ssh/known_hosts

不過由於這個檔案包含所有連線過的主機金鑰,所以若整個刪除的話,其他主機的金鑰之後也要重新抓取,如果不想這樣的話,也可以開啟這個設定檔,把對應的那一行主機金鑰刪除即可。

自動加入未知的主機金鑰

有時候我們會需要撰寫指令稿,自動連線至許多台 Linux 主機進行控制,由於 ssh 在第一次連線到新的主機時,會詢問是否加入新的主機金鑰,如果在指令稿要連線的主機非常多的話,每一台都要手動輸入 yes 來新增主機金鑰是一件非常累人的事情。

遇到這種狀況我們就可以關閉 StrictHostKeyChecking 這個主機金鑰檢查功能,讓 ssh 自動將沒看過的主機金鑰加入 ~/.ssh/known_hosts 紀錄檔中:

# 自動加入未知的主機金鑰,不要詢問
ssh -o StrictHostKeyChecking=no seal@myhost.gtwang.org

參考資料:鳥哥的 Linux 私房菜TecmintTecmintDigitalOceanDigitalOcean