VPN 上 SSH 每分钟断开?问题不在 keepalive
以固定间隔断开的会话,通常是丢了防火墙状态,而不是 keepalive。先追查两个方向,再动 MTU 或定时器。
SSH 连上后能工作一分钟左右,然后每次都会在几乎相同的间隔卡死。常见的解释是空闲超时,于是人们调低 MTU、设置客户端 keepalive。我曾处理过的一条 WireGuard 链路已经把这些都试过了:更小的隧道 MTU、客户端保活设置、配置好的隧道保活。掉线依旧不变。原因其实是一条不对称的 LAN 路由,这个模式值得记住,因为它能击败所有基于定时器的修法。
keepalive 只能证明你的主机仍愿意发送,它无法让有状态设备看到一条从未经过它的回包。
误区:keepalive 能修复无声断开
SSH keepalive 只做一件事:防止某个按静默计时的机制回收空闲会话。这件事它做得很好。它解决不了有状态设备的问题——该设备只看到某个方向的第一个包,此后再没看到回包,因为客户端发什么都不会改变回包走哪个接口。
改 MTU 是另一种流行做法,失败方式却一样。降低 MTU 有助于分片和路径 MTU 问题,对路由毫无作用。如果你的定时器和 MTU 已经合理,断开仍以固定间隔出现,那么间隔说明某处存在超时,而不是包大小。把间隔记下来,和路径上每台设备的状态超时逐一比较。
特征是规律性,加上会话在该间隔内仍然可用。空闲超时发生在什么都没做的时候;这个却发生在你打字的时候。
多出来的网关到底做了什么
把笔记本和 VPN 网关放在同一网段,用另一台 LAN 防火墙做默认网关。笔记本把去往 VPN 的流量发给防火墙,防火墙再转给网关,而 网关的回包直接经 LAN 返回笔记本。第二段从不经过防火墙,所以它的状态表只保留了半个连接。
下面的地址反映了这种布置:
Laptop: 192.168.50.20
LAN firewall: 192.168.50.1
WireGuard gateway: 192.168.50.10
Remote VPN subnet: 10.77.0.0/24重定向和状态处理随后会把一次能用的握手变成“晚一点才死”的连接。延迟来自状态表项老化或更严格的检查失败,所以间隔看起来如此机械。
这些都不出现在客户端配置里,所以排查常常从错误的文件开始。
只选一条明确的路径
对上面的布置来说,把远端网段直接路由到 VPN 网关就能消除半个连接:
sudo ip route add 10.77.0.0/24 via 192.168.50.10
ip route get 10.77.0.42这些是示例地址。下一跳必须能在你的 LAN 内到达,前缀必须是目标远端网络,第二条命令会先给出结果,再让你依赖它。如果网关不在你的网段里,这条路由就不是你要的修法。
如果防火墙的职责是管控这两套系统之间的流量,绕开它就是错误设计。应当让两个方向都穿过边界,并在两侧配置路由,使回程路径一致。目标是单一明确的路径,而不是减少状态检查。
Netgate 的 关于非对称路由的说明 描述了同样的接口级不对称及其带来的状态问题,所以在全局放宽状态处理之前先读一读。与本案类似的定时断线本身并不是证据。把文章看作一种故障模式的描述,然后在改动全局状态策略之前,先证明你自己的网络符合它。
从两端测试
读笔记本去往目的地的路由,以及目的地回笔记本的路由;这是两个独立的判断,而且很可能只有一个是错的。从网关本身发出的 ping 成功,反而可能完全掩盖问题,因为它从路径本来就正确的那台机器发出。你需要的是真实会话两端各自看到的那两个方向。
修复后重新打开 SSH,让会话保持到远超原先失败的间隔。然后把路由写进已批准的网络配置里长期保留,因为一次性命令不是重启方案,下次重启时问题还会带着新的谜团回来。
什么时候不对称没问题
非对称路由在很多网络里都正常,按定义并不算坏。当状态跟踪、地址转换或策略依赖于看到一条它看不到的路径时,它才成为问题,而每种情况的解法都不同。重新设计之前,先确认中间设备到底需要什么。
持久的答案会点明两条路径、需要同时看到两者的那台设备,以及让这成为可能的那条路由。如果你说不出是哪台设备,说明你还没找到原因。