一、ssh命令
登錄類型
- 密碼登錄: 服務器發送公鑰給客戶端,客戶端使用公鑰加密后回傳給服務器,服務器解密驗證密碼。
- 公鑰登錄: 服務器發送一個隨機字符串給客戶端,客戶端用私鑰加密,服務器用公鑰解密(rsa作為簽名使用)
ssh命令相關參數
- -A 密鑰轉發 這個參數在使用跳板機等場景非常有用,如果發現始終連不上需要檢查下這個
- -i 指定密鑰文件
- -p 端口號
- -C:請求壓縮所有數據;
- -f 后台運行
- -N 參數: 不要求分配shell,有些場景下ssh禁止賬號請求shell終端,比如這個賬號只是作為轉發
- -g 默認這個LocalPort端口只允許本機連接,可以通過這個參數允許別的機器連接這個端口
- -T :不要求分配終端
- -o ServerAliveInterval=60 隔段時間發送保活消息
- -q 抑制一些調試性的額外輸出
- -v 顯示詳細的調試信息,如果ssh連不上可以使用這個參數看看哪一步出問題了
相關的命令
- ssh-keygen 用於生成密鑰對
- ssh-copy-id 用於復制公鑰到服務器
復制公鑰也可以使用:ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
相關的文件
- ~/.ssh/authorized_keys 用於保存用戶的公鑰文件
- ~/.ssh/known_hosts文件 保存的服務器用於辨別服務器的唯一散列碼
- ~/.ssh/id_dsa 用戶的私鑰文件
- ~/.ssh/id_rsa.pub 默認生成的用戶的公鑰文件,用於將該公鑰追加到需要登錄的服務器authorized_keys文件
- /etc/ssh/ssh_config 客戶端ssh配置
- /etc/ssh/sshd_config 服務端ssh配置
使用模式
這里推薦一種使用的模式,在利用腳本做自動化的時候,可以利用ssh操作遠程主機,這種方式可以靈活的運用管道,使用了重定向,如上面修改authorized_keys。例:
將遠程主機$HOME/src/目錄下面的所有文件,復制到用戶的當前目錄:ssh user@host 'tar cz src' | tar xzv
將$HOME/src/目錄下面的所有文件,復制到遠程主機的$HOME/src/目錄: cd && tar czv src | ssh user@host 'tar xz'
二、端口轉發
動態轉發:ssh -D 1080 user@host -Nfg
最廣泛的用途是作為sock5代理,另外還有加密連接的附加好處,廣泛使用的ss軟件就是用的這個。
另外還可以作為跳板機實現,公網的服務器有些沒有外網ip,通過有外網的服務器作為代理去訪問那些只有內網ip的服務器。
本地轉發:ssh -L LocalPort:remoteHost:remotePort sshHost
注意這里remoteHost:remotePort是相對於sshHost的地址,比如remoteHost設置為localhost,實際就是sshHost本地
一般用於無法直連的場景,比如防火牆,沒有開發公網端口等, 本地不能直接連接remoteHost,需要用sshHost來做中轉。
當時我們公司的一個場景,我們的服務器一些后台沒有開通外網端口,在公司內部我們需要訪問后台,利用內網的一台服務器ssh本地轉發到公網服務器,我們在內網直接訪問內網服務器。
遠程轉發:ssh -R LocalPort:remoteHost:remotePort sshHost
注意這里remoteHost:remotePort是相對於ssh命令執行的機器的和本地轉發不同。
另外注意這個命令執行和機器和本地轉發不同。比如我們有這么個需求,將服務器serverA的21端口映射到client的2021。
本地轉發:這時我們在客戶機上執行本地轉發命令,ssh -L 2021:localhost:21 serverA
遠程轉發: 則是在服務器上運行,ssh -R 2021:localhsot:21 client,client指的是我們的客戶機,也就是說client需要有sshServer
上面的本地轉發和遠程轉發很像,同樣的功能命令差在一個參數,但兩者有時候不可相互取代。本地和遠程從數據的出口來記:
本地:客戶端連接sshServer將本地的數據轉發到本地端口轉發出去
遠程: 客戶端連接sshServer,在sshServer建立端口,數據從sshServer到本地來
一般用於公網訪問局域網的場景。在局域網的機器建立遠程轉發讓公網的服務器可以訪問局域網
xsell中 菜單->查看—>隧道窗格中可以快速創建這三種類型。
三、跳板機登錄
很多時候線上服務器的權限管理是通過跳板機來控制的,比如服務器a,b,c你不能直接連接,而是通過先登錄跳板機再去連接。如果你現在想在本地連接服務器,有如下方案:
- 在本地使用動態轉發,如
ssh -D 1080 user@host主機和用戶使用的是跳板機,在xshell中新建連接時使用1080作為代理,此時你可以將這個連接認為是跳板機在連,比如你在連接中填寫localhost,這個localhost到時就是跳板機 - 在本地使用本地轉發,如
ssh -L 2222:hosta:22 tiaobanHost,這時候我們就可以使用localhost和2222端口在連接服務器a,不需要配置代理 - 遠程轉發一般不用,因為服務器不能訪問公司的局域網
上面的方法雖然可以實現登錄后端服務器,但是兩部操作還是有些不便,可以使用更方便的ProxyCommand。
該方法也有兩種形式:
ssh -o ProxyCommand="ssh user@jumpHost -W %h:%p" serverHostssh -o ProxyCommand="nc -x jumpHost:jumpPort %h:%p" serverHost
這個命令如果經常使用可以將ProxyCommand寫入到ssh的配置文件中
現在有三個機器
- 客戶機:192.168.199.3
- 跳板機:192.168.199.6
- 目標機:192.168.199.5
第一種執行:ssh -o ProxyCommand="ssh 192.168.199.6 -W %h:%p" 192.168.199.5
注意這個-W是在新版中才加入,openssh 5.4之后才支持,相當於簡化版的nc
客戶機進程:
chen 50607 50529 0 17:52 pts/0 00:00:00 ssh -o ProxyCommand=ssh 192.168.199.6 -W %h:%p 192.168.199.5
chen 50608 50607 0 17:52 pts/0 00:00:00 ssh 192.168.199.6 -W 192.168.199.5:22
客戶機顯示的連接:
tcp 0 0 192.168.199.3:34306 192.168.199.6:22 ESTABLISHED 50608/ssh
跳板機顯示的連接:
tcp 0 0 192.168.199.6:36932 192.168.199.5:22 ESTABLISHED -
tcp 0 0 192.168.199.6:22 192.168.199.3:34306 ESTABLISHED -
目標機顯示的連接:
tcp 0 0 192.168.199.5:22 192.168.199.6:36932 ESTABLISHED -
從上面的結果可以看到,跳板機和兩頭各建立了一個連接,另外客戶機是50608進程占用了這個連接
第二種執行:ssh -o ProxyCommand="ssh 192.168.199.6 nc %h %p" 192.168.199.5
這種方式和方面的一樣,顯示的連接也都一致。
最后說說一種nc
注意這種方式需要有個sock5代理,所以跳板機先開啟代理:ssh -D 4000 192.168.199.5 -Nfg
nc支持多種代理,包活scok4,sock5和http,這種方式和上面的兩種完全不同。有一點很奇怪如果跳板機沒開sock5代理也沒有任何報錯信息,ssh並沒有
並沒有使用代理而是直接連接目標服務器
ssh -o ProxyCommand="nc -x 192.168.199.6:4000 %h %p" 192.168.199.5
四、scp 命令
例子:scp test.txt chen@centos:/home/chen/data/
- -P 指明端口
- -r 遞歸復制
- -i 指明密鑰文件
五、rsync命令
例子: rsync -avuz ~test/ chen@centos:/home/chen/data/
rsync命令和scp類似,主要是采用'rsync'算法只同步不同的文件,支持壓縮傳輸和斷點續傳,一般情況下速度更快。參數如下:
- -t 不更新modify time
- -z 壓縮
- -P 斷點續傳功能,大文件用到
- -r 遞歸傳遞
- -I 強制同步
- -a 歸檔模式並保持所有文件屬性, 等價於-rlptgoD (no -H,-A,-X)
- -v 輸出傳輸詳情
- -u 如果接受者上的文件比傳輸者的新舊不同步
指定端口,如1280端口: rsync -ravuz -e 'ssh -p 1280' 192.168.10.10:/home/chenfangzhi/ .
另外rsync還有一種服務器模式,采用rsync服務端和客戶端的模型,需要長期同步文件,推薦使用這種模式,這種模式的賬號和linux系統賬號是分開的,更加安全。
六、 ssh-agent
最后說的這個東西是非常有用的,如果經常使用的ssh的肯定會遇到需要用多個私鑰的場景和私鑰被加密的場景。如果私鑰被加密,每次連接還是需要輸入密碼,
當在各個服務器之間穿可能需要多次id_rsa密碼,很是繁瑣,另外多個多個主機采用不同的私鑰的時候需要指定私鑰,ssh-agent就是用來解決這個問題的。
這個功能需要在sshd配置文件中配置AllowAgentForwarding,ssh配置文件中配置ForwardAgent
- eval `ssh-agent -s` :開啟agent,這里必須使用eval
- ssh-add id_rsa_file:用來添加密鑰,這里如果不指定文件則添加的是~/.ssh/id_rsa文件
七、ssh執行命令不退出問題
我們在批量執行服務器命令經常會用到ssh host command命令,但是在有時候發現這個命令不能正常退出,說下這種模式下命令正常退出的條件:
- 遠程的執行的進程執行完成或者放入后台運行
- 如果是放入后台運行要保證該進程或子進程的標准輸入輸出和當前ssh進程沒有聯系
這種問題經常出現的場景是,我去批量啟動服務器上的服務,調用start.sh腳本之后(ssh host "bash start.sh &"),發現無法退出。這時候我采用了
ssh host "nohup bash start.sh &",發現還是不能正常退出。最后查了下就是上面的兩個原因,因為start.sh腳本中啟動了新的進程,子進程繼承了bash進程文件描述符,
也就是輸入輸出都和bash相同,和ssh進程還有聯系。所以改寫為:ssh host "bash start.sh &>out.log &"成功運行。
另外說說nohup這個命令,在這里其實nohup是完全沒必要使用的,一方面是因為nohup是為了忽略SIGHUP信號,但是如果是使用ssh host command這種模式的話,進程是不會和終端綁定也就是進程不會
收到SIGHUP信號。另一方面是nohup是在執行的進程的標准輸入和輸出綁定了終端時會重定向,但是這個場景下,標准輸入輸出已經被重定向到了管道。
ssh有個-t參數,如果加入這個參數,則會默認分配一個終端,上面的邏輯就變了,需要使用nohup來進行重定向。但是我發現如果是使用ssh -t host "nohup bash start.sh &>out.log &"啟動進程還會導致進程無法啟動的問題,網上說是ssh進程退出的太快了,導致nohup被殺死。但是&后面不能sleep函數,語法報錯。一種方法是start.sh中啟動服務地方加入&,然后上面改寫成ssh -t host "nohup bash start.sh &>out.log;sleep 1"
重定向的問題參看上面紅字
我在虛擬機的實驗結果如下:
[chen@cc1 ~]$ ssh root@192.168.199.5 "TMPSPID=\$(ps -ef | grep -v grep |grep -e 'sshd.*notty' | awk '{print \$2}');echo \$TMPSPID;ls -l /proc/\$TMPSPID/fd;echo \$\$;ls -l /proc/\$\$/fd"
root@192.168.199.5's password:
14719
total 0
lrwx------. 1 root root 64 May 28 21:37 0 -> /dev/null
lrwx------. 1 root root 64 May 28 21:37 1 -> /dev/null
l-wx------. 1 root root 64 May 28 21:37 11 -> pipe:[122988]
lr-x------. 1 root root 64 May 28 21:37 12 -> pipe:[122989]
lr-x------. 1 root root 64 May 28 21:37 14 -> pipe:[122990]
lrwx------. 1 root root 64 May 28 21:37 2 -> /dev/null
lrwx------. 1 root root 64 May 28 21:37 3 -> socket:[122854]
lrwx------. 1 root root 64 May 28 21:37 4 -> socket:[122951]
lr-x------. 1 root root 64 May 28 21:37 5 -> pipe:[122954]
l-wx------. 1 root root 64 May 28 21:37 6 -> /run/systemd/sessions/94.ref
l-wx------. 1 root root 64 May 28 21:37 7 -> pipe:[122954]
14725
total 0
lr-x------. 1 root root 64 May 28 21:37 0 -> pipe:[122988]
l-wx------. 1 root root 64 May 28 21:37 1 -> pipe:[122989]
l-wx------. 1 root root 64 May 28 21:37 2 -> pipe:[122990]
八、sz和rz命令
這兩個命令十分方便,在Windows下使用xshell客戶端,如果遇到跳板機這種場景,需要頻繁的穿來穿去,這兩個命令可以自動穿隧道,十分方便,命令本省十分簡單。
- -e 采用二進制傳輸,這個非常重要,有時候在傳輸可執行文件時
- -y 如果存在則覆蓋原文件,默認是生成一個
