我在操作系统重启后打开了一个反向 ssh 隧道(在办公室电脑上到专用服务器)。我通过 将其放入 cron@reboot /myssh.sh
中。ssh 在服务器上打开一个端口。
我的问题是:
如果操作系统(办公室电脑)突然死机并再次启动,则 cron 将再次运行脚本,而服务器上的端口仍被上一个会话使用,当然 ssh 将失败(因为它试图打开服务器上的开放端口)。这就是为什么如果办公室电脑重新启动,我无法从服务器访问办公室电脑的原因。
问题:
- 如何在办公室电脑上重新打开反向 ssh 之前检查服务器上的 ssh 或端口(并结束上一个会话)?
- 我是否必须通过访问器端(服务器)或主机端(办公室电脑)来完成此操作?
目标
我希望无论发生什么情况,ssh 隧道都能保持活动状态。如果互联网连接丢失,只要互联网可用,我仍然可以访问办公室电脑。
答案1
使用控制插座
我刚刚发现了似乎最正确的方法自动SSH。
然而多路复用是一个非常大的课题,可以用于其他事物。来源
这个想法Bash 脚本设置...是使用和集成方法称为控制插座。通过此方法,您可以命令关闭旧连接。但是您必须测试此方法在重启后是否有效。
您的要求是:
终止远程服务器上的进程
隧道是在远程机器上运行的一个进程。您可以生成一个脚本来验证隧道的先前实例是否正在运行。
假设这ssh -f -R XXXXX:localhost:YYYYY user@server -N
是您的原始命令。XXXXX
代表远程服务器上使用的端口,YYYYY 代表本地计算机上的端口。
XXXXX
然后,您可以使用以下命令检查远程服务器上没有进程正在监听端口lsof。但是你需要能够使用sudo
为了获取进程 ID(进程号) 是监听该端口的程序。
一旦你找到进程号使用端口,您只需在服务器上运行命令即可kill thePID
。
用于获取 PID 的 Bash 脚本
下面的脚本应该显示进程号正在监听XXXXX
并保存在/tmp/remTunPID
。如果您的用户没有须藤访问它将不起作用,出于安全原因,PID 将不可见。
脚本:
#!/bin/bash
rPort=XXXXX
theUser=[replace with remote user name]
server=[replace with your server]
if [ -a /tmp/sshPID1 ]
then
rm /tmp/sshPID1
fi
if [ -a /tmp/sshPID2 ]
then
rm /tmp/sshPID2
fi
if [ -a /tmp/remTunPID ]
then
rm /tmp/remTunPID
fi
echo "Enter [sudo] password for ${theUser}:"
ssh -t $theUser@$server "sudo lsof -i tcp:${rPort} | grep IPv4" > /tmp/sshPID1
while read -a A; do echo ${A[6]}; done < /tmp/sshPID1 > /tmp/sshPID2
cat /tmp/sshPID2 | grep -v pass | tee /tmp/remTunPID
if [ -s /tmp/remTunPID ]
then
thePID=$(cat /tmp/remTunPID)
echo The process $thePID is running at $server listening to $rPort
else
echo No process is listening on $rPort at $server
fi
将 和rPort
的值分别更改为您的远程端口、远程用户和服务器(域或 IP)的值。theUser
server
此命令将提示您输入须藤密码才能继续,但如果你懂一点,不用担心狂欢你可以看到它被直接请求远程控制带有-t
选项。
实际终止进程
您可以在此脚本的语句中添加一个命令if then else fi
来终止该进程:
if [ -s /tmp/remTunPID ]
then
thePID=$(cat /tmp/remTunPID)
echo The process $thePID is running on $server and listening on $rPort
echo Will attempt to kill $thePID
ssh $theUser@$server "kill ${thePID}"
else
echo No process is listening on $rPort
fi
仅当端口正在使用时,此操作才会终止进程。但即使您的机器最初没有启动隧道,它也会终止进程。