SSH 基本用法
最近小夥伴們紛紛進了實驗室,就冒出了一系列關於控制遠程機器的問題,我覺得我還是有必要科普一下的。首發於博客:https://abcdabcd987.com/ssh/
約定
- 本文不講解 Linux 使用方法,只講解機器之間的通信方法。
- 下文中行首的 local$ 以及 remote$ 等為命令行的提示符,不是輸入的內容,用於區分當前是在哪台機子上。
基礎
在 Linux 系統上 SSH 是非常常用的工具,通過 SSH Client 我們可以連接到運行了 SSH Server 的遠程機器上。SSH Client 的基本使用方法是:
ssh user@remote -p port
- user 是你在遠程機器上的用戶名,如果不指定的話默認為當前用戶
- remote 是遠程機器的地址,可以是 IP,域名,或者是後面會提到的別名
- port 是 SSH Server 監聽的埠,如果不指定的話就為默認值 22
實際上,知道了上面這三個參數,用任意的 SSH Client 都能連接上 SSH Server,例如在 Windows 上 PuTTY 就是很常用的 SSH Client。
local$ ssh user@remote -p port user@remotes password:
在執行了 ssh 命令之後,遠程機器會詢問你的密碼。在輸入密碼的時候,屏幕上不會顯示明文密碼,也不會顯示 ******,這樣別人就不會看到你的密碼長度了,按下回車即可登入。
登入之後,你就可以操作遠程機器啦!
安裝 OpenSSH Server
local$ ssh user@remote -p port ssh: connect to host remote port 22: Connection refused
如果你遇到了上面的消息,說明在遠程機器上沒有安裝 SSH Server,特別地,如果遠程機器運行的是 Ubuntu Desktop 系統,那麼默認是沒有安裝 SSH Server 的。這個時候,你可以聯繫管理員讓他安裝 SSH Server,或者如果你有 sudo 許可權的話,可以執行下面命令安裝:
sudo apt-get install openssh-server
免密碼登入
每次 ssh 都要輸入密碼是不是很煩呢?與密碼驗證相對的,是公鑰驗證。也就是說,要實現免密碼登入,首先要設置 SSH 鑰匙。
執行 ssh-keygen 即可生成 SSH 鑰匙,一路回車即可。Windows 用戶可以使用 PuTTY 配套的 PuTTYgen 工具。
local$ ssh-keygenGenerating public/private rsa key pair.Enter file in which to save the key (/home/user/.ssh/id_rsa):Created directory /home/user/.ssh.Enter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /home/user/.ssh/id_rsa.Your public key has been saved in /home/user/.ssh/id_rsa.pub.The key fingerprint is:SHA256:47VkvSjlFhKRgz/6RYdXM2EULtk9TQ65PDWJjYC5Jys user@localThe keys randomart image is:+---[RSA 2048]----+| ...o...X+o|| . o+ B=Oo|| .....ooo*=|| o+ooo.+ .|| .SoXo. . || .E X.+ . || .+.= . || .o || |+----[SHA256]-----+
這段話告訴了我們,生成的公鑰放在了 ~/.ssh/id_rsa.pub,私鑰放在了 ~/.ssh/id_rsa。接下來,我們要讓遠程機器記住我們的公鑰。最簡單的方法是 ssh-copy-id user@remote -p port
local$ ssh-copy-id user@remote -p port/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_rsa.pub"/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keysuser@remotes password:Number of key(s) added: 1Now try logging into the machine, with: "ssh user@remote -p port"and check to make sure that only the key(s) you wanted were added.
ssh-copy-id 在絕大多數發行版上都有預裝,在 Mac 上也可以通過 brew install ssh-copy-id 一鍵安裝。
在沒有 ssh-copy-id 的情況下(比如在 Windows 上),也是可以輕鬆做到這件事的。用命令的話也是一句話搞定
ssh user@remote -p port mkdir -p .ssh && cat >> .ssh/authorized_keys < ~/.ssh/id_rsa.pub
這句話的意思是,在遠端執行新建 .ssh 文件夾,並把本地的 ~/.ssh/id_rsa.pub (也就是公鑰)追加到遠端的 .ssh/authorized_keys 中。當然,不使用這條命令的話,你也可以手動操作這個過程,即先複製公鑰,再登入遠程機器,粘貼到 .ssh/authorized_keys 當中。
在完成這一步之後,ssh 進入遠程機器時就不用輸入密碼了。Windows 用戶在 PuTTY 上面設置登入用戶名和 PuTTYgen 生成的私鑰之後也可以免密碼登入。
配置別名
每次都輸入 ssh user@remote -p port,時間久了也會覺得很麻煩,特別是當 user, remote 和 port 都得輸入,而且還不好記憶的時候。配置別名可以讓我們進一步偷懶。
比如我想用 ssh lab 來替代上面這麼一長串,那麼在 ~/.ssh/config 裡面追加以下內容:
Host lab HostName remote User user Port port
保存之後,即可用 ssh lab 登入,如果還配置了公鑰登入,那就連密碼都不用輸入了。
Windows 用戶使用 PuTTY 直接保存配置即可。
傳輸文件
在兩台機之間傳輸文件可以用 scp,它的地址格式與 ssh 基本相同,都是可以省略用戶名和埠,稍微的差別在與指定埠時用的是大寫的 -P 而不是小寫的。不過,如果你已經配置了別名,那麼這都不重要,因為 scp 也支持直接用別名。scp 用起來很簡單,看看下面的例子就明白了:
# 把本地的 /path/to/local/file 文件傳輸到遠程的 /path/to/remote/filescp -P port /path/to/local/file user@remote:/path/to/remote/file# 也可以使用別名scp /path/to/local/file lab:/path/to/remote/file# 把遠程的 /path/to/remote/file 下載到本地的 /path/to/local/filescp lab:/path/to/remote/file /path/to/local/file# 遠程的默認路徑是家目錄# 下面命令把當前目錄下的 file 傳到遠程的 ~/dir/filescp file lab:dir/file# 加上 -r 命令可以傳送文件夾# 下面命令可以把當前目錄下的 dir 文件夾傳到遠程的家目錄下scp -r dir lab:# 別忘了 . 可以用來指代當前目錄# 下面命令可以把遠程的 ~/dir 目錄下載到當前目錄裡面scp -r lab:dir/ .
Windows 用戶可以使用 PuTTY 配套的 PSCP。
如果覺得使用命令行傳輸文件渾身不自在,你還可以使用 SFTP 協議。任何支持 SFTP 協議的客戶端都能用你的 SSH 賬號信息登入並管理文件,比如開源的有圖形化界面的FTP客戶端 FileZilla。別忘了,在這些客戶端裡面,你也可以指定你的私鑰(~/.ssh/id_rsa),然後就能做到無密碼登入了。
保持程序在後台運行
有時候你想要在遠程的機器上跑一個需要長時間運行的程序,比如一些計算,然後當你睡了一覺再登入遠程的機子上卻發現什麼結果都沒有。這是因為一旦 ssh 進程退出,所有它之前啟動的程序都會被殺死。那麼有什麼辦法可以保持程序在後台運行呢?
你需要在遠程的機子上使用 tmux。tmux 是一個會話管理程序,他會保持程序一直運行著。在 Ubuntu 上你可以通過 sudo apt-get install tmux 來安裝。
remote$ tmux
這樣你就進入到了 tmux 管理的會話中,之後你再運行任何東西都不會因為你退出 ssh 而被殺死。要暫時離開這個會話,可以先按下 ctrl+b 再按下 d。要恢復之前的會話,只需要執行
remote$ tmux attach
tmux 還能管理多個窗口、水平豎直切分、複製粘貼等等,你可以看看這篇不錯的文章來入門。
如果你是Mac用戶,那麼十分幸運的是,你幾乎不需要任何學習,只要把你的終端由系統自帶的 Terminal 換成 iTerm 2。iTerm 2 自帶超好的 tmux 支持,你可以像操作本機的標籤頁一樣操作 tmux 會話。你只需要在新建會話的時候使用 tmux -CC,在恢復的時候使用 tmux -CC attach 即可。具體的可以參見 iTerm2 and tmux Integration。
最後強調一遍,tmux 應該運行在遠程的機子上,而不是本機上,否則程序在 ssh 退出時依然會被殺死。
反向埠轉發:例子1
相信很多人都會有這樣的需求:我實驗室的機器和宿舍的機器都處在區域網中,但我需要在宿舍訪問實驗室的機器,或者反過來。這個時候,你需要一台處在公網的機器,如果沒有的話,可以考慮騰訊雲或者阿里雲的學生優惠。
假設現在你有一台處在公網的機器 jumpbox,這台機器是在任何地方都能訪問到的;你在實驗室也有一台機子 lab,這台機子只能在實驗室內部訪問,但他可以訪問公網,你希望能在任何地方都能訪問這台機器。使用 ssh -R 可以輕鬆地做到這個事情。
lab$ ssh -R 10022:localhost:22 jumpboxjumpbox$ ssh user@localhost -p 10022lab$
如果上面這個過程成功了,就說明在你執行 ssh -R 10022:localhost:22 jumpbox 之後,你成功地將 lab 上的 22 埠反向轉發到了 jumpbox 的 10022 埠。只要保持這個 ssh 不斷,任何一台機器都可以首先連接到 jumpbox,然後通過 ssh user@localhost -p 10022 連回到 lab。可以看到,這裡 jumpbox 起到了一個跳板的作用,所以我們把它稱作跳板機。
不過上面這麼做並不穩健,如果因為網路波動導致 ssh -R 那個連接斷了,那麼從 jumpbox 就完全失去了到 lab 的控制。萬幸的是,有一個叫做 autossh 的軟體,可以自動的檢測斷線,並在斷線的時候重連。在 Ubuntu 上你可以使用 sudo apt-get install autossh 來安裝,在 Mac 上則是 brew install autossh。
lab$ autossh -NfR 10022:localhost:22 jumpbox
上面這句話裡面 -N 表示非不執行命令,只做埠轉發;-f 表示在後台運行,也就是說,這句話執行之後 autossh 就在後台默默工作啦;-R 10022:localhost:22 就是把本地的22埠轉發到遠程的10022埠。
現在,任何一台電腦先連上跳板機,就可以連回內網的機子啦!
你甚至可以將這句話設置為開機時運行:在 /etc/rc.local 裡面 exit 0 這句話之前加上
su - user -c autossh -NfR 10022:localhost:22 jumpbox
其中 user 是你的用戶名。需要注意的是,如果你需要開機時運行 autossh,你需要配置公鑰登入,因為開機運行的時候是沒有交互界面讓你來輸入密碼的。
這裡順帶說一句,你可以綁定1024到65535之間的任意埠,只要這個埠之前沒有程序在用就行。
反向埠轉發:例子2
還是反向埠轉發,再舉一個很常見的例子:我在本地跑了一個網站,我想臨時把我的網站發給朋友看看。你可以很容易的復現這個實驗:在本地運行 python -m SimpleHTTPServer 即可在本地的8000埠啟動一個網站,你可以在瀏覽器中通過 http://localhost:8000/ 看到。下面我們想讓遠方的朋友看到這個網站。
local$ ssh -NR 0.0.0.0:18000:localhost:8000 jumpbox
遠方的朋友即可通過 http://jumpbox:18000/ 看到了。注意到這裡和上面的命令有一個小小的不同,就是多了 0.0.0.0,這告訴 ssh,要把18000埠綁定在遠端的所有IP上。如果像之前那樣省略的話,預設值是只綁定在 localhost,也就是只有在 jumpbox 本機才可以訪問,而其他人都不能訪問。
反向埠轉發:例子3
比方說在本地的127.0.0.1:1080運行了HTTP代理服務,現在我想讓另一台機子 remote 也能夠使用這個HTTP代理。
local$ ssh -NR 11080:localhost:1080 remotelocal$ ssh remoteremote$ export http_proxy=http://127.0.0.1:11080/remote$ export https_proxy=http://127.0.0.1:11080/remote$ curl http://ifconfig.co
看看返回的IP,是不是 remote 也用上了代理?
正向埠轉發
反向埠轉發是把本機的埠轉發到遠程的機子上;與之對應,正向埠轉發則是把遠程的埠轉發到本地。
比方說,之前我們把 lab 的22埠反向轉發到了 jumpbox 的10022埠,現在我想把它轉發到本機的20022埠,只需要執行 ssh -L 就行了,例如:
local$ ssh -NL 20022:localhost:10022 jumpboxlocal$ ssh localhost -p 20022lab$
用作 SOCKS5 代理
要是想要在家訪問公司內網的一些網站,但是公司又沒有提供進入內網的VPN,那怎麼辦呢?通過 ssh -D 可以在本地建立起一個 SOCKS5 代理:
local$ ssh -ND 1080 workplace
如果 workplace 處在內網,不要忘記前面講到可以用反向埠轉發和跳板機來解決這個問題。現在,你可以在瀏覽器的設置裡面,把代理伺服器設成 socks5://127.0.0.1:1080,然後你就可以看到 workplace 能看到的所有網站啦。
傳遞圖形界面
上面我們都是在運行命令行程序,那如果遠程有一些程序是不得不用圖形界面的話,是不是無解了呢?實際上,恰恰相反,X11的設計天生就支持這樣的行為。
首先,我們需要在本機裝上 X Server:Linux 桌面用戶本身就已經有了 X Server,Windows 用戶可以使用 Xming,Mac 用戶需要使用 XQuartz。
安裝好了 X Server 之後,我們通過 ssh -X 進行連接,例如:
local$ ssh -X remoteremote$ xeyes
現在你應該會看到一對傻傻的眼睛,這就說明成功了,注意,這個眼睛是跑在遠程的,而輸入和輸出都是在本地。這個方法幾乎可以運行任何圖形界面的程序,比如你可以試試看運行 nautilus 或者 firefox。
Update (2016-08-13 23:41): 感謝評論中 @大哥哥 提醒,把 "forwarding" 的翻譯由「映射」改為「轉發」
推薦閱讀:
※如何修改 Linux 設備訪問許可權
※學習linux驅動開發的方法?
※如何看待加密即時通信APP——安司密信?
※ssh遠程登陸有時候正常,有時候顯示:ssh_exchange_identification: Connection closed by remote host,這是什麼原因?
※既然 Windows 在用戶量和生態體系上都能碾壓 Linux,為什麼還有人說 Linux 比 Windows 好?