我有一台远程 Raspberry Pi 计算机,它通过反向 SSH 隧道从其限制性防火墙后面连接到我的服务器。想象一下,这台 Raspberry Pi 位于另一个国家/地区难以进入的建筑物屋顶上(可能正在下暴风雨),所以我希望它的连接可靠。
为了连接到服务器,Raspberry Pi 运行如下过程:
while true; do
ssh -R 19999:localhost:22 www.sern.pro
sleep 30
done
这部分19999:localhost:22
基本上意味着服务器上端口 19999 上的所有流量都应转发到 Raspberry Pi 的端口 22。因此,我可以通过 SSH 连接到服务器,然后运行以下命令来连接到 Raspberry Pi:
ssh localhost -p 19999
这通常可以正常工作,并且在服务器上,netstat --all --timers --program --numeric | egrep '127.0.0.1:*(LISTEN|.*)' | sort
类似这样的命令会列出反向 SSH 连接,如下所示:
tcp 0 0 127.0.0.1:19999 0.0.0.0:* LISTEN 2972/5 off (0.00/0/0)
然而,偶尔我发现服务器上的这个列表消失了Raspberry Pi 仍保持与服务器的 SSH 连接也就是说,该命令ssh localhost -p 19999
会导致如下错误信息:
ssh: connect to host localhost port 19999: Connection refused
然而,Raspberry Pi SSH 连接仍然完好无损,能够在服务器上运行命令。当发生这种情况时,我不知道该用什么词来描述出了什么问题。
那么……除了预订航班和爬上楼顶,我怎样才能再次将此活动的 SSH 连接作为正确的反向 SSH 隧道?我如何才能再次访问本地端口?
答案1
十多年前,autossh
人们就为这样的目的编写了实用程序。
您可以使用以下连接脚本
#!/bin/sh
export AUTOSSH_GATETIME=0
autossh -M 0
-o "PubkeyAuthentication=yes" \
-o "StrictHostKeyChecking=false" \
-o "PasswordAuthentication=no" \
-o "ExitOnForwardFailure=yes" \
-o "ServerAliveInterval 60" \
-o "ServerAliveCountMax 3" \
-fNR 19999:localhost:22 www.sern.pro
当然,您需要在启动此脚本之前建立基于密钥的身份验证。
答案2
您看到的问题意味着连接不可用,如果您在列出所有连接的命令末尾检查,您可能会看到该端口的连接不再处于 LISTEN 状态,而是处于 TIME-WAIT 或 CLOSE-WAIT 状态,这意味着连接仍然“活跃”,但仅作为 raspberry 中的运行进程。
为了使其正常工作,您可以创建一个脚本,如果尚未设置,则检查是否存在 reversessh 连接。
为了解决这个问题,您可以向脚本中添加代码来检查设备上是否有 ssh 进程 id,如果您有一个标记文件,那么您可以终止该进程以重新启动隧道。
例如,您有一个名为 RESTARTSSH 的空文件,您可以在脚本中检查该文件是否存在,如果存在,则搜索 ssh 的进程 id 并将其终止,然后重新启动隧道。
要检查进程 ID,您可以使用:
ps -ef | grep ServerAliveInterval | grep -v grep | awk '{print $2}'