在macOS上用supervisor構建穩定的SSH轉發
之前一直使用SSH指定端口轉發請求,一直能用,但是很煩。因爲每次都要輸入密碼之類的,而且經常會斷開,斷開後又輸密碼,神煩。前幾日決心解決這個問題,作爲一名Python開發者,首先想到的就是supervisor,最後也證明這個想法行得通。
先 brew install supervisor
把它安裝上,然後運行 brew service start supervisor
運行起來。打開 /usr/local/etc/supervisor.d
,然後在下面建立一個 ssh_d.ini
文件,內容如下:
[program:ssh_d] command=你的SSH命令 autostart=true autorestart=true numprocs=1 killasgroup=true stopasgroup=true
其中 autostart
和 autorestart
參數能夠確保你的SSH進程始終在。然後運行 supervisorctl start ssh_d
把它運行起來。但這一步不一定能夠成功,因爲你可能沒有配置免密碼登陸服務器。
ssh-keygen -t rsa
可以爲自己生成配對的公鑰和密鑰,注意保存的文件名,以免和其它服務器的混了,比如我自已輸入的是 ssh_d_id_rsa
。
生成後,把 ssh_d_id_rsa
文件放到 ~/.ssh/
目錄下。用 scp
把 ssh_d_id_rsa.pub
上傳到你的服務器,並把它加到服務器的 ~/.ssh/authorized_keys
文件中。然後配置本機的 /etc/ssh/ssh_config
文件,加上這麼一節:
Host 你的主機IP SendEnv LANG LC_* IdentityFile ~/.ssh/ssh_d_id_rsa
這時候你再試試 supervisorctl restart ssh_d
,估計就能運行成功了。可以在瀏覽器裏試一下代理,有沒有轉發請求出去。
以上,基本上使用起來就沒有問題了。不過好像時間久了SSH進程會有點不靠譜,具體啥原因也不好深究,我的方案是定時,15分鐘,讓 supervisor
重啓一次SSH進程。
在macOS上做定時任務,一開始我是延用了 crontab
,發現各種折騰,都沒有效果。最後靠譜的是 launchd
。具體的操作是先把 supervisor
重啓進程的命令寫成腳本,比如 ~/supervisorctl_restart_ssh_d.sh
,內容如下:
#!/bin/sh /usr/local/bin/supervisorctl restart ssh_d
保存後,注意用 chmod +x
給這個腳本文件加上可執行權限,不然就會失敗。
下一步是進入 ~/Library/LaunchAgents
目錄,然後寫一個 ssh_d.crontab.plist
的文件,裏面的內容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>ssh_d.crontab</string> <key>ProgramArguments</key> <array> <string>改成你的supervisorctl_restart_ssh_d.sh文件的絕對路徑</string> </array> <key>StartInterval</key> <integer>900</integer> <key>RunAtLoad</key> <true/> <key>StartInterval</key> <integer>900</integer> <key>RunAtLoad</key> <true/> <key>Debug</key> <true/> <key>StandardErrorPath</key> <string>/tmp/AlTest1.err</string> <key>StandardOutPath</key> <string>/tmp/AlTest1.out</string> </dict> </plist>
然後運行 launchctl load ssh_d.crontab.plist
裝裁這個命令,成功的話,你可以看到你的SSH的進程ID變化了,這就表示它成功重啓了SSH進程。
另外也可以用命令來查看任務運行的結果:
launchctl list | grep ssh_d - 0 ssh_d.crontab
中間的 0 表示運行成功,如果是非 0 值,比如 78,可以使用另一個命令來看看是表示什麼意思:
launchctl error 78 78: Function not implemented
至此,SSH進程常用常新,可用性增強了不少。
不過如果合上mac的屏幕,較長時間之後再打開,你會發現SSH連接已經斷開,但並不會自動重連。
目前這個痛點還沒有好的解決方案。我暫時是用瀏覽器打開 http://127.0.0.1:9001
頁面,這是 supervisor
的Web控制檯。然後手動啓一下 ssh_d
,因爲不需要輸入密碼,而且這種情況一天也沒有幾次,尚可接受。
如果你打不開 http://127.0.0.1:9001
,可以編輯 /usr/local/etc/supervisord.ini
文件,把下面兩行前面的註釋去除,
[inet_http_server] ; inet (TCP) server disabled by default port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface
然後再運行 brew service restart supervisor
就可以了。
更新:
一覺醒來,有了靈感:屏幕亮起,也就是由睡眠到喚醒,是一種事件啊。 launchd
應該有機制可以獲取這個事件,然後做一些事情的。一搜索,果然有方法。具體就是在 ssh_d.crontab.plist
文件中加入下面這幾行:
<key>WatchPaths</key> <array> <string>/Library/Preferences/SystemConfiguration</string> </array>
原理是當喚醒macOS時,這個文件夾(也就是系統配置)會有一些變化,比如WIFI之類的,所以當這個文件夾變化時,就重啓一下我們的SSH進程,就不需要再手動去重啓了。
真香。