SSH远程端口转发失败


26

后续行动:看起来像是一系列快速断开连接,同时每台服务器都运行了几个月,这可能是偶然的,只是用来揭示实际问题。未能重新连接的原因几乎可以肯定是由于AliveInterval值(卡巴斯德的回答)。使用ExitOnForwardFailure选项应该允许超时在重新连接之前正确发生,这在大多数情况下应该可以解决问题。MadHatter的建议(kill脚本)可能是确保隧道可以重新连接的最佳方法,即使其他一切都失败了。

我在防火墙后面有一个服务器(A),该服务器在多个端口上启动了到小型DigitalOcean VPS(B)的反向隧道,因此我可以通过B的IP地址连接到A。隧道已经连续工作了大约3个月,但在过去的24小时内突然发生了四次故障。同一件事发生在另一家VPS提供商身上-几个月的完美运行,然后突然出现了多次快速故障。

我在机器A上有一个脚本,该脚本会自动执行tunnel命令(ssh -R *:X:localhost:X address_of_B针对每个端口X),但是在执行时会显示Warning: remote port forwarding failed for listen port X

进入/var/log/secure服务器上的sshd会显示以下错误:

bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X

解决方法是重新启动VPS。在此之前,所有尝试重新连接的消息都会显示“远程端口转发失败”消息,并且将无法正常工作。现在到了隧道仅持续约4个小时才停止的地步。

VPS上没有任何变化,它是一次性使用的单用户计算机,仅充当反向隧道终结点。它在CentOS 6.5上运行OpenSSH_5.3p1。似乎当连接断开时,sshd不会关闭其末端的端口。我无所适从地解释了为什么,或者为什么经过数月近乎完美的运行现在突然会发生这种情况。

为了澄清,我首先需要弄清楚为什么sshd在隧道故障后拒绝侦听端口,这似乎是sshd使端口保持打开状态并且从不关闭它们引起的。这似乎是主要问题。我只是不确定在经过数月的预期运行后会导致这种行为的原因(即立即关闭端口并允许脚本重新连接)。


你的问题是什么?如何解决端口绑定错误,或者如何找出ssh即将死的原因或其他原因?
MadHatter在2014年

我需要弄清楚为什么sshd拒绝打开VPS上的端口(绑定错误)。端口绑定错误似乎是问题的根源,如果我能够解决问题,那么一切都会正常进行。
贾斯汀·姆克瓦

2
对于任何较晚的潜伏者,无需手动创建脚本来保持连接打开,只需使用autossh即可,这可以为您完成。serverfault.com/questions/598210/…–
oligofren

Answers:


27

我同意MadHatter的观点,它很可能是来自失效ssh连接的端口转发。即使您当前遇到的问题是其他问题,您也可能迟早会遇到这种已失效的ssh连接。

可以通过以下三种方式终止连接:

  • 两个端点之一重新启动,而连接的另一端完全空闲。
  • 两个端点之一关闭了连接,但是在关闭连接时,连接暂时中断。断开连接后,中断持续了几分钟,因此另一端从未得知断开的连接。
  • 在ssh连接的两个端点上,该连接仍完全起作用,但是有人在它们之间的某个位置放置了有状态的设备,由于空闲,该设备使连接超时。此状态设备将是NAT或防火墙,您已经提到的防火墙是主要的可疑对象。

找出发生上述三种情况中的哪一种并不是很重要,因为有一种方法可以解决所有这三种情况。那就是使用keepalive消息。

您应该查看ClientAliveInterval关键字for sshd_config和或的ServerAliveInterval间隔。ssh_config~/.ssh/config

ssh循环运行命令可以正常工作。最好在循环中插入一个睡眠,这样当由于某种原因连接失败时,您就不会淹没服务器。

如果客户端在服务器上的连接终止之前重新连接,则您可能会遇到新的ssh连接处于活动状态但没有端口转发的情况。为了避免这种情况,您需要ExitOnForwardFailure在客户端使用关键字。


我认为这可能是问题所在。特别是,如果ssh进程终止,我在A上的脚本将尝试重新连接到B(当然,由于警告消息不会杀死ssh进程,因此它只会在发生这种情况时挂起,但这又是一个问题)。但是,如果A尝试过快地重新连接到B,则B可能正在等待A重新连接。我可能需要确保B在A重新连接之前总是超时。结合MadHatter的建议,即在重新连接之前终止sshd进程,可能会覆盖95%的可能情况。
贾斯汀·姆克瓦

1
谈到警告消息没有杀死SSH,这让我开始思考...并查看联机帮助页。原来-o ExitOnForwardFailure yes正是我需要的。因此,这是我需要弄清楚的一件事。想一想,我打算编写一个Python脚本来解析这些警告消息。这要简单得多。:D
贾斯汀·穆尔克瓦

抱歉ExitOnForwardFailure在写我的答案时忘记了。我现在将其添加到答案中。
卡巴斯德(Kasperd)

4
没问题,实际上是-o ExitOnForwardFailure=yes(请注意等号)。因此,如果有人遇到此问题,请勿复制和粘贴我之前的评论,否则将无法使用。:P
贾斯汀·穆尔克瓦

因此,我一直在监视服务器大约10个小时,并且看起来运行良好。我现在假设这个答案是正确的(根据我所看到的,我大约有99%的把握),并且一系列快速断开是与网络问题相关的巧合,而网络问题恰好在几个月后才出现启动每项服务。感谢大家的帮助。;)
Justin Mrkva

4

您可以找到与该服务器上的端口绑定的过程

sudo netstat -apn|grep -w X

似乎很可能已经半途不知了sshd,但是为什么在可以拥有数据的时候做出假设呢?这也是脚本在尝试再次启动隧道之前找到PID并将信号9发送到的好方法。


我记得在以前的VPS提供程序上进行过检查,并确认sshd是侦听这些端口的过程。下次发生这种情况时,我将在此处进行检查,但是由于行为和设置完全相同,所以我认为它不会有任何不同。
贾斯汀·姆克瓦

太好了,让您的脚本重新打开隧道后,再尝试杀死旧的隧道。
MadHatter支持Monica 2014年

如果您要说的话,一次运行的隧道脚本(在A上)不会超过一个。另一方面,如果您要让脚本在B上远程执行命令以杀死流离失所的进程……这实际上不是一个坏主意。但是,如果我要调试,一个顾虑是反复终止所有SSH连接。如果A上的脚本总是由于故障而杀死B,那么我就不会经常被流氓A脚本踢离B。:P我必须进行测试以确保它不会那样做。但是就像我说的,这不是一个坏主意。;)
Justin Mrkva

我没想到那里。您说远程服务器上正在运行一个脚本,由于绑定错误,该脚本试图建立隧道并失败,并且我假设它仅在需要时运行(即,当现有隧道不好时)因为你没有说其他的话。我所建议的是,在尝试启动新隧道之前,它会终止使端口保持打开状态的特定过程。
MadHatter在2014年

运行ssh的脚本仅在服务器A上,服务器B是普通的普通服务器,没有其他脚本。我可能要做的是编写一个kill脚本放在服务器B上,然后如果它不能连续连接一定次数,则从A远程调用它。这样,它不太可能干扰其他SSH连接。而且,如果调用脚本的次数太多或太快,我可能会在每次运行和退出时都拥有kill脚本日志,而无需执行任何操作。就个人而言,似乎限制任何杀死sshd的脚本都是谨慎的。:P
贾斯汀·穆尔克瓦

3

对我来说,当ssh隧道断开连接时,需要一段时间才能重置连接,因此该ssh过程继续受阻,没有活动的隧道,我也不知道为什么。一种变通方法是在不使用旧连接重置的情况下,将其ssh置于后台-f并生成新连接。该-o ExitOnForwardFailure=yes可用于LIMT新进程的数量。这样-o ServerAliveInterval=60可以提高当前连接的可靠性。

您可以ssh经常重复执行该命令,例如,在cron脚本中的或循环中,例如,在下面的示例中,我们ssh每3分钟运行一次命令:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done

一种方式更强大的解决方案将使用autossh
马可Lavagnino

-o ExitOnForwardFailure=yes是我一直在寻找的东西,非常感谢!
vadipp '18

1

以我的经验,如果远程系统上仍在运行“某物”,则ssh会有一个令人讨厌的习惯,即不能干净地退出。例如从后台开始。您可以通过以下方式重现此内容:

ssh <server>
while true; do  sleep 60; done&
exit

您的ssh将注销,但实际上不会关闭会话-直到远程进程退出(它不会退出,因为这是“ while true”循环)。可能正在发生类似的事情-您的会话被ssh生成了一个“卡住”的进程。该端口仍在使用中,因此您的本地进程无法重用该端口。


在A机上执行的完整SSH命令是ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &这样的,因此,除了隧道本身(特别是由于-N选项)之外,SSH没有执行任何其他操作。使用sshd本身在远程服务器B上执行任何保持打开状态的操作。
贾斯汀·姆克瓦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.