如何可靠地保持SSH隧道打开?


234

我下班时使用SSH隧道来绕过各种隐性防火墙(我的老板没关系:))。问题是,一段时间后,ssh连接通常会挂起,并且隧道断开。

如果我至少可以自动监视隧道,则可以在挂起隧道时重新启动它,但我什至没有想办法。

可以告诉我如何防止ssh连接挂起的用户的加分点,当然!


您的隧道因不活动而死了吗?我在通过电话建立端口隧道时遇到了这个问题,因此我最终结束了使用以下watch命令在连接上生成虚拟命令以使其“处于活动状态” watch -n1 60 echo "wiiiii"。除非网络断开或您不使用它,否则隧道不会消失。
erm3nda

Answers:


280

听起来您需要autossh。这将监视ssh隧道并根据需要重新启动它。我们已经使用了两年了,它似乎运作良好。

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

有关-M参数的更多详细信息,请参见此处


2
+1表示autossh,它的功能与锡盒上的要求相同。我相信其功能的一部分还在于发送保持活动风格的数据包,以防止任何形式的超时。
肯特

30
您能否在示例中使用示例隧道autossh
Ehtesh Choudhury 2012年

5
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com 您可能会注意到,我使用-nNT设置了此设置,该设置不会创建远程终端,因此我可以将autossh置于后台,并使用-i选项让SSH使用.pem文件。如果您要一直保持连接打开,我绝对建议您进行额外的设置。
juckele,2015年

2
对于它的价值,似乎最好省略该-M参数:bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162
rinogo 2015年

2
我这样做是为了让它在网络更改后重试,对我来说效果很好:autossh -M 0 -o“ ServerAliveInterval 10” -o“ ServerAliveCountMax 2” -L 9999:localhost:19999 server@example.com
Luke Stanley

39

所有有状态的防火墙在一段时间内都没有看到该连接的数据包后会忘记连接(以防止状态表充满连接,而两端都死了而不关闭连接)。大多数TCP实现会在很长一段时间后发送keepalive数据包,而不会听到对方的声音(2小时是一个常见值)。但是,如果有状态防火墙在发送keepalive数据包之前忘记了连接,那么长寿但空闲的连接将消失。

如果是这种情况,解决方案是防止连接变为空闲。OpenSSH具有一个称为ServerAliveInterval的选项,该选项可用于防止连接空闲太长时间(作为奖励,即使连接处于空闲状态,它也会检测对等端何时较早死亡)。


指定的间隔以秒为单位,因此您可以进行一些微调。如果您的状态防火墙的空闲超时为5分钟,则60或120秒足以保持连接打开。这是我通过家用路由器保持ssh会话打开的方式之一。
达伦·霍尔

谢谢,这有所帮助。但是请注意(此处是排名较低的答案,superuser.com / a / 146641/115515),如果您指定ServerAliveInterval而不是ServerAliveCountMax,则可能会发现ssh故意比您想要的更快地断开连接。
metamatt 2012年

4
@metamatt,您引用的排名较低的答案是出于充分原因而排名较低的:它是错误的。
Lambart 2014年

24

在您自己的Mac或Linux计算机上,配置ssh使服务器ssh每3分钟保持活动状态。打开一个终端,然后将您不可见的.ssh放入家中:

cd ~/.ssh/ 

然后使用以下命令创建一个1行配置文件:

echo "ServerAliveInterval 180" >> config

您还应该添加:

ServerAliveCountMax xxxx (high number)

默认值为3,因此ServerAliveInterval 180将在9分钟(ServerAliveInterval指定的3分钟间隔中的3分钟)后停止发送。


2
请注意,如果您已经有配置文件,则不建议您使用该命令。使用>>进行重定向会更好!
珀尔帖

为什么ServerAliveInterval 180给我们6分钟?直觉使我尝试这样:180/60 == 3。那么,是否ServerAliveInterval可以30秒的倍数工作?
nemesisfixx 2011年

@mcnemesis:ServerAliveInterval 180表示3分钟。ServerAliveCountMax默认值为3表示这些间隔为3,即9分钟。
metamatt 2012年

2
我之所以投票赞成此答案,是因为感谢您提到ServerAliveCountMax,以及如果指定不带ServerAliveCountMax的ServerAliveInterval会发生什么。但是,就像前面的评论一样,我注意到“将在以后停止发送”的计算是错误的,并且我认为如果仅给出有关这些选项的信息,而不是告诉我们如何使用cd和echo命令应用它们,则此答案会更好。 。
metamatt 2012年

20
拒绝投票是因为将ServerAliveCountMax设置为“高数字”没有意义。ServerAliveCountMax指定在放弃之前它将尝试发送“ keepalive”消息的次数。默认值为3,因此使用ServerAliveInterval 180时,如果服务器在9分钟后未响应,则它将仅停止发送,在这种情况下,您的连接可能正常并且确实死了。
Lambart 2014年

22

我使用以下Bash脚本在上一个死亡时继续产生新的ssh隧道。当您不想或无法安装其他软件包或使用编译器时,使用脚本非常方便。

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

请注意,这需要一个密钥文件来自动建立连接,但是autossh也是如此。


2
您应该添加任何理由要在autossh上使用此脚本,或者仅仅是这样更容易?
kyrias 2012年

4
如果ssh自身冻结,这将无济于事,不是吗?
2013年

1
如果您无法在服务器中安装东西,它将很有帮助。autossh没有预先安装,有时会变得很钝。
Quarkex

是的,最好不必安装东西。一年以来,我一直以这种方式进行操作,这是保持远程计算机可访问性的唯一方法(甚至将crontab设置为在重新引导时运行它)。它永远不会失败,更重要的是,我知道为什么它永远不会失败。
sudo

16

Systemd非常适合于此。

创建一个/etc/systemd/system/sshtunnel.service包含以下内容的服务文件:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(修改ssh命令以适合)

  • 这将以用户身份运行,sshtunnel因此请确保该用户首先存在
  • systemctl enable sshtunnel将其设置为在启动时启动的问题
  • 问题systemctl start sshtunnel立即开始

2018年1月更新:某些发行版(例如Fedora 27)可能使用SELinux策略来阻止从systemd init使用SSH,在这种情况下,将需要创建自定义策略以提供必要的豁免。


2
这看起来与我的主旨非常相似:gist.github.com/guettli / ...欢迎反馈!
guettli

非常适合systemd系统。如果使用,Restart=on-failure则手动终止SSH客户端将不会导致系统成功重启,因为SSH客户端成功退出。
David Tonhofer,

如果您想从作为参数提供的(bash)脚本启动ssh ExecStart,例如以构建ssh参数列表,请进行基本检查等,然后像这样从脚本中调用它exec /bin/ssh -N ...。这是我的命令:exec /bin/ssh -N -oExitOnForwardFailure=Yes -oTCPKeepAlive=no -oServerAliveInterval=5 -oServerAliveCountMax=6 -i "${LOCAL_PRIVATE_KEY}" -L "${TUNNEL_INLET}:${TUNNEL_OUTLET}" "${REMOTE_USER}@${REMOTE_MACHINE}"其中,TUNNEL_INLET="127.0.0.1:3307"TUNNEL_OUTLET="127.0.0.1:3306"
大卫Tonhofer

10

在我看来,您肯定误解了ServerAliveCountMax。据我了解文档,这是在不终止连接的情况下无法应答的服务器活动消息的数量。因此,在类似我们此处讨论的情况下,将其设置为高值只会确保不会检测到并终止挂起的连接!

只需设置ServerAliveInterval就足以解决防火墙忘记连接的问题,而将ServerAliveCountMax设置为低电平将使始发端能够注意到失败并在连接失败时终止。

您想要的是,1)在正常情况下使连接永久保持打开状态,2)检测到连接失败并在发生故障时退出发起方,3)每次重新发出ssh命令退出(您的操作取决于平台,Jawa建议的“ while true”脚本是一种方法,在OS XI上实际设置了启动项)。


9

ServerAliveInterval如果隧道问题是由过期的NAT会话生成的,请始终使用SSH选项。

如果连接完全中断,请始终使用重生方法,此处至少有三个选项:

  • autossh程序
  • bash脚本(while true do ssh ...; sleep 5; done)不会删除sleep命令,ssh可能会很快失败,并且您将重新生成太多进程
  • /etc/inittab,要访问在NAT之后在另一个国家/地区发货和安装的盒子,而无需将端口转发到盒子,则可以对其进行配置,以创建一条回送给您的ssh隧道:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • Ubuntu上的upstart脚本,该脚本/etc/inittab不可用:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

或始终使用两种方法。


1
内联选项+1,以防您不希望所有SSH连接都使用它
2014年

您写“以防连接性完全下降”。现在我不明白,autossh可以解决哪些问题,而不能解决什么问题?我想当然可以解决任何断开的连接,例如拔掉电缆几个小时,但是也许不会吗?
Mads Skjern

6

我用这个解决了这个问题:

编辑

~/.ssh/config

并添加

ServerAliveInterval 15
ServerAliveCountMax 4

根据ssh_config的手册页

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session.  It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below).  The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable.  The TCP keepalive option enabled by
         TCPKeepAlive is spoofable.  The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3.  If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds.  This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server.  The
         default is 0, indicating that these messages will not be sent to
         the server.  This option applies to protocol version 2 only.

每隔15秒似乎经常对服务器执行ping操作。
Lambart 2014年

@Lambart,但是如果连接确实不稳定并且经常断开连接,则至少会检测到连接中断,并有机会更早地重试。
binki 2014年

4

ExitOnForwardFailure yes是其他建议的好辅助。如果它已连接但无法建立端口转发,则对您来说就像没连接一样毫无用处。


这是一个很好的主意。如果以前的连接在远程端比在本地主机中更早超时,则即使autossh也没用,因为在这种情况下,本地主机将尝试再次连接,但由于端口仍处于打开状态,因此无法建立转发。
劳尔·萨利纳斯-蒙塔古多

1

我需要长期维护SSH隧道。我的解决方案是从Linux服务器上运行的,它只是一个小的C程序,它使用基于密钥的身份验证重新生成ssh。

我不确定悬挂的位置,但是由于超时,我的隧道已经消失了。

我很乐意为重生器提供代码,但现在似乎找不到。


1

虽然有诸如autossh之类的工具可以帮助重新启动ssh会话...我发现真正有用的是运行“ screen”命令。即使断开连接,它也允许您恢复ssh会话。如果您的连接不够可靠,则特别有用。

...如果可以帮助您,请别忘了标记这是“正确”的答案!;-)


7
...但是问题是关于如何使SSH隧道保持打开状态,而不仅仅是终端会话。屏幕很棒!
肯特2009年

我已经使用屏幕了,但是并不能解决我的问题:-/不过,谢谢您的回答。
珀尔帖

1

有点骇人听闻,但我喜欢使用屏幕来保持这种状态。我目前有一个已经运行了数周的远程转发。

从本地开始的示例:

screen
ssh -R ......

应用远程转发后,并且远程计算机上具有外壳程序:

screen
Ctrl + a + d

您现在有了不间断的远程转发。诀窍是在两端都运行屏幕


1

最近我自己遇到了这个问题,因为如果您使用密码登录,这些解决方案要求您每次都重新输入密码,所以我在循环中使用了sshpass以及文本提示,以避免在批处理文件中包含密码。

以为我会在这个主题上分享我的解决方案,以防其他人遇到相同的问题:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done

0

我以前的ISP遇到过类似的问题。对我来说,任何tcp连接,访问网站或发送邮件都是一样的。

解决方案是通过UDP配置VPN连接(我正在使用OpenVPN)。这种连接对导致断开的原因更加宽容。然后,您可以通过此连接运行任何服务。

连接仍然可能存在问题,但是由于隧道将具有更大的容忍度,因此任何ssh会话都会感到短暂的停顿,而不是被断开。

为此,您需要在线提供VPN服务,您可以在自己的服务器上进行设置。


0

由于autossh不能满足我们的需求(如果第一次尝试无法连接到服务器,就会出现错误),因此我们编写了一个纯bash应用程序:https : //github.com/aktos-io/link-与服务器

默认情况下,它为服务器上NODE的sshd端口(22)创建反向隧道。如果您需要执行其他任何操作(例如转发其他端口,通过连接发送邮件等),则可以放置脚本on-connecton-disconnect文件夹。

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.