天天看点

在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进程,就不需要再手动去重启了。

真香。

继续阅读