我从远程树莓派设置了多个反向 ssh 隧道,运行 debian jessie。RPI 使用 3G 加密狗来获得 Intrnet 连接,这就是我使用反向 ssh 远程登录的原因。每个 RPI 设置到云服务器的反向 ssh 隧道,我用它来登录每个系统。
ssh隧道设置如下:
ssh -N -o ExitOnForwardFailure=yes -R 23xx:localhost:22 [email protected]
其中 23xx 是用于转发来自端口 22 的连接的端口,而 178.xxxxx 是服务器的 IP 地址。
我的问题是,有时当我尝试 ssh 进入系统时,它会永远挂起,没有错误,如下所示:
ssh pi_username@localhost -p 23xx
此后终端不输出任何内容并永远挂起。当我尝试使用 -vvv 进行调试时,这是我得到的:
ssh pi_username@localhost -p 23xx -vvv
OpenSSH_6.7p1 Debian-5+deb8u4, OpenSSL 1.0.1t 3 May 2016
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to localhost [::1] port 23xx.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.7p1 Debian-5+deb8u4
看起来连接已建立,但没有提示登录。有任何想法吗?关于如何进一步调试的任何建议?
这只是一个理论,但我怀疑正在发生的是您的 ssh 会话的 TCP 连接正在死亡,但“云服务器”没有检测到它。所以当你去建立一个连接时
localhost -p 23xx
,ssh 进程仍然在那里并且正在监听,但是当它试图将数据发送回 Pi 时,它会挂起,直到遇到最大的 TCP 重传次数,最后决定连接已死并退出(您说它永远挂起,但我敢打赌,如果您等待的时间足够长,您会重置连接)。现在假设您已将 Pi 配置为在 ssh 隧道死亡时重新连接,您可能认为这应该解决问题。这个想法有几个潜在的问题。首先是 Pi 也可能没有检测到死连接。因此,在它尝试发送数据并达到 TCP 重传限制之前,它不会看到死连接并进行重新连接。第二个潜在问题是,即使它确实检测到死连接并尝试重新连接,它也无法在云服务器上建立侦听器,因为之前的 ssh 仍然存在并保持在端口上。
这里的解决方案是配置 ssh 以便它可以检测到死连接。有几种方法可以解决这个问题,TCP KeepAlive 和 SSH KeepAlive。(参考:https ://unix.stackexchange.com/a/34201/4358 )
TCP KeepAlive(
TCPKeepAlive
在 ssh 配置中设置)使用 TCP 的原生 keep-alive 功能。基本上内核每 X 秒发送一个空的 TCP ACK,当它没有从另一端收到一个 ACK(或它得到一个重置)时,它会关闭通知应用程序(SSH)的连接。SSH KeepAlive(
ServerAlive*
&ClientAlive*
设置)类似,但在更高层运行。在这里,SSH 进程通过连接发送实际数据并寻找响应。这应该与正常的 TCP KeepAlive 一样检测到死连接,但是它更有可能保持连接处于活动状态,因为中间的跃点可以识别 TCP KeepAlive 数据包并忽略它们,并使空闲连接超时。但是无法识别 SSH KeepAlive,因为它看起来像是到中间任何跃点的真实流量。TL;博士:
在树莓派上,将以下设置添加到您的 ssh 客户端配置(
~/.ssh/config
或/etc/ssh/ssh_config
):(文档)
在服务器上,将以下设置添加到您的 ssh 守护进程配置 (
/etc/ssh/sshd_config
):(文档)
请注意,我将间隔值设置得稍高。这样做的原因只是为了让双方不会在完全相同的时间发送他们的 KeepAlive 消息并在网络上相互交叉。这并没有真正的危害,只是效率低下。哪一边更高也没有关系,只要它们不同即可。
我遇到了同样的问题。
将 mtu 值更改为 1200。 ( MTU )
SSH 在此之后按预期连接。希望这个答案可以缩短您对解决方法的搜索。:)