之前一直使用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

其中 autostartautorestart 參數能夠確保你的SSH進程始終在。然後運行 supervisorctl start ssh_d 把它運行起來。但這一步不一定能夠成功,因爲你可能沒有配置免密碼登陸服務器。

ssh-keygen -t rsa 可以爲自己生成配對的公鑰和密鑰,注意保存的文件名,以免和其它服務器的混了,比如我自已輸入的是 ssh_d_id_rsa

生成後,把 ssh_d_id_rsa 文件放到 ~/.ssh/ 目錄下。用 scpssh_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進程,就不需要再手動去重啓了。

真香。

相關文章