2009-09-08 13:04:22 +0000 2009-09-08 13:04:22 +0000
244
244

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

我在工作中使用SSH隧道来绕过各种idotic防火墙(我的老板也没意见:)。问题是,过了一段时间,ssh连接通常会挂掉,隧道也会被破坏。

如果我至少能自动监控隧道,我可以在它挂掉的时候重新启动隧道,但我甚至还没有想出办法。

能告诉我如何防止我的ssh连接挂起的人,当然要加分!!。

答案 (16)

296
296
296
2009-09-08 13:43:51 +0000

听起来你需要 autossh 。这将监控ssh隧道并在需要时重新启动它。我们已经用了好几年了,看起来效果不错。

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

更多关于-M参数的细节 这里

40
40
40
2009-09-28 13:47:26 +0000

所有有状态的防火墙在一段时间内没有看到一个连接的数据包后,都会忘记这个连接(以防止状态表中充满了两端都没有关闭连接就死亡的连接)。大多数TCP实现会在长时间没有收到对方的消息后发送keepalive数据包(2小时是一个常见的值)。但是,如果有一个有状态的防火墙,在发送keepalive数据包之前就忘记了这个连接,那么一个长期存在但闲置的连接就会死亡。

如果是这种情况,解决方案是防止连接变成空闲。OpenSSH有一个叫做 ServerAliveInterval 的选项,可以用来防止连接空闲太久(作为奖励,即使连接空闲,它也会检测到对等体什么时候死的更快)。

24
24
24
2010-05-29 13:45:08 +0000

在你自己的mac或linux机器上配置你的ssh,让服务器ssh每3分钟活一次。打开一个终端,进入你家里的隐形.ssh。

cd ~/.ssh/

然后创建一个1行的配置文件:

echo "ServerAliveInterval 180" >> config

你还应该添加:

ServerAliveCountMax xxxx (high number)

默认值是3,所以ServerAliveInterval 180会在9分钟后停止发送(ServerAliveInterval指定的3分钟间隔的3)。

23
23
23
2009-09-22 14:58:15 +0000

我使用了下面的 Bash 脚本来在前一个隧道死掉的时候继续生成新的 ssh 隧道。当你不想或不能安装额外的包或使用编译器时,使用脚本是很方便的。

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

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

21
21
21
2016-07-28 06:10:14 +0000

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,在这种情况下,将需要创建一个自定义策略来提供必要的豁免。

11
11
11
2013-11-28 01:04:34 +0000

在我看来,你们肯定都误解了ServerAliveCountMax。根据我对文档的理解,它是指在不终止连接的情况下可以不被回复的服务器活着的消息的数量。因此,在我们讨论的这种情况下,将它设置为一个高值只会确保挂起的连接不会被检测到并被终止。

简单的设置ServerAliveInterval应该足以解决防火墙忘记连接的问题,而将ServerAliveCountMax设置为低值,则可以让发起端注意到失败,如果连接还是失败,则终止。

你想要的是,1)在正常情况下连接永久保持打开状态,2)连接失败被检测到,发起端在失败时退出,3)每次退出时重新发出ssh命令(如何做到这一点非常依赖于平台,Jawa建议的 “while true "脚本是一种方法,在OS X上我其实设置了一个launchd项)。

9
9
9
2014-03-08 21:30:40 +0000

始终使用ServerAliveInterval SSH选项,以防隧道问题是由过期的NAT会话产生的。

在连接完全中断的情况下,始终使用重生方法,你在这里至少有三个选项。

  • autossh程序
  • bash脚本(while true do ssh ...; sleep 5; done) 不要去掉睡眠命令,ssh可能会很快失败,你会重生太多的进程
  • /etc/inittab,要想访问一个在另一个国家运来并安装在NAT后面的盒子,不需要端口转发到盒子上,你可以配置它创建一个ssh隧道回到你身边。

-Ubuntu上的upstart脚本,/etc/inittab不可用。

或者一直使用这两种方法。

6
6
6
2013-05-30 13:32:05 +0000

我用这个方法解决了这个问题。

编辑

~/.ssh/config

添加

ServerAliveInterval 15
ServerAliveCountMax 4

根据man page for 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.
4
4
4
2015-06-06 23:41:10 +0000

ExitOnForwardFailure yes是其他建议的一个很好的辅助手段。如果它连接了,但不能建立端口转发,对你来说就像它根本没有连接一样没有用。

1
1
1
2012-03-13 12:11:18 +0000

有点黑,但我喜欢用屏幕来保持这个。我目前有一个远程转发,已经运行了几个星期。

示例,在本地启动。

screen
ssh -R ......

当远程转发被应用时,你在远程计算机上有一个shell,

screen
Ctrl + a + d

现在你有一个不间断的远程转发。技巧是在两端运行屏幕

1
1
1
2015-07-30 14:02:55 +0000

最近我自己也遇到了这个问题,因为这些解决方案要求你每次都要重新输入密码,如果你使用密码登录的话,我就用sshpass在循环中加上一个文本提示,以避免在批处理文件中出现密码。

我想我应该把我的解决方案分享给大家,以防有人有同样的问题:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done
``` 。
1
1
1
2009-09-08 14:09:33 +0000

虽然有像autossh这样的工具可以帮助重启ssh会话……我发现真正有用的是运行 “screen "命令。它可以让你在断开连接后重新启动ssh会话。如果你的连接不那么可靠的话,那就特别有用。

…不要忘了标记这是'正确'的答案,如果它能帮助你k!;-)

1
1
1
2009-09-08 13:17:28 +0000

我有一个长期维护SSH-tunnel的需求。我的解决方案是在Linux服务器上运行的,它只是一个小的C程序,使用基于密钥的认证重新启动ssh。

我不清楚挂起的情况,但我有过隧道因超时而死的情况。

我很想提供重生器的代码,但现在好像找不到了。

0
0
0
2017-07-15 00:04:11 +0000

由于autossh不能满足我们的需求(如果在第一次尝试时不能连接到服务器,它就存在错误),我们写了一个纯bash程序。 https://github.com/aktos-io/link-with-server

它默认为服务器上NODE的sshd端口(22)创建一个反向隧道。如果你需要执行任何其他操作(比如转发额外的端口,在连接上发送邮件等等……),你可以将你的脚本on-connecton-disconnect文件夹。

0
0
0
2009-09-28 10:27:21 +0000

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

解决方法是配置一个UDP的VPN连接(我用的是OpenVPN)。这种连接对任何导致断线的情况都比较宽容。然后你可以通过这个连接运行任何服务。

连接上还是会有问题,但是由于隧道会更加宽容,任何ssh会话都会感觉到短暂的中断,而不是被断开。

要做到这一点,你需要一个在线的VPN服务,你可以在自己的服务器上设置。

0
0
0
2020-02-20 15:09:46 +0000

你可以很简单地在远程服务器上使用tmux命令,它允许你在远程机器上打开 “会话",在那里你将运行你的远程代码。它允许你在远程机器上打开一个 "会话",在那里你将运行你的远程代码。

然后你就可以退出(或者在你的情况下失去连接)远程机器而不用担心,因为你的代码在你的tmux会话中安全运行。

最后,当你在远程服务器上重新连接时,你只需要tmux attach回到你之前打开的会话,就可以了。