在 Linux VM 里启动 Tailscale 后,当前 SSH 连接立刻断开。这个问题看起来像 sshd 异常,但很多时候真正原因是:Tailscale 接收了子网路由,并插入了优先级更高的策略路由,导致 SSH 回包被导向 tailscale0。
现象
执行:
1 | tailscale up --accept-routes=true |
当前 SSH 连接马上断开。
重新登录后直接看原始输出:
1 | ip rule |
重点看两处:
5270: from all lookup 52:table 52排在main前面。192.168.39.0/24 dev tailscale0:SSH 客户端所在网段可能被 Tailscale 接管。
这说明 Tailscale 的 table 52 比系统默认的 main 路由表更早被查询。如果 SSH 客户端所在网段也被 Tailscale 接管,SSH 回程就可能被抢走。
先确认 SSH 客户端 IP
不要先猜网段,先看当前 SSH 连接来自哪里:
1 | ss -tnpa | grep sshd |
这里服务端本地地址是 172.16.10.3:22,SSH 客户端地址是:
1 | 192.168.39.3 |
后面的排查都要围绕这个客户端 IP 做,不要凭印象写一个管理网段。
查看 SSH 回程走哪里
拿 SSH 客户端 IP 查路由。如果回程被 Tailscale 抢走,通常会看到类似输出:
1 | ip route get 192.168.39.3 |
重点看 dev tailscale0 和 table 52,这说明 SSH 回包会从 Tailscale 出去。
正常情况下,回程应该走 VM 原来的网卡,例如:
1 | ip route get 192.168.39.3 |
这里的 eth0、网关和网段都要按真实环境替换。
查看 Tailscale 策略路由
继续看策略路由和 Tailscale 路由表,建议把命令和输出一起贴出来:
1 | ip rule |
重点看两件事:
lookup 52是否排在lookup main前面。table 52里是否有 SSH 客户端所在网段,比如192.168.39.0/24 dev tailscale0。
Linux 策略路由里,pref 数值越小,优先级越高。这里 5270 小于 32766,所以会先查 Tailscale 的 table 52,再查 main 表。
根因
SSH 请求从 VM 原网卡进来:
1 | client -> eth0 -> sshd |
但启动 Tailscale 并接收子网路由后,回包查路由时先命中 table 52:
1 | sshd -> tailscale0 -> client |
请求从 eth0 进,回包却从 tailscale0 出,路径不一致,当前 SSH 连接就会断开。
所以这个问题的核心不是 sshd 挂了,而是 SSH 管理流量的回程路由被改了。
临时修复
给 SSH 客户端网段加一条更高优先级规则,强制走 main 表:
1 | ip rule add to 192.168.39.0/24 pref 90 lookup main |
这里的 90 小于 Tailscale 的 5270,所以会先命中这条规则。
验证时也直接看命令输出:
1 | ip route get 192.168.39.3 |
重点看 dev eth0。如果仍然是 dev tailscale0,说明网段、客户端 IP 或规则优先级需要继续检查。
DNS 也要检查
有时 SSH 恢复后,DNS 仍然异常。可以先拿当前 DNS 服务器地址:
1 | DNS=$(awk '/^nameserver/{print $2; exit}' /etc/resolv.conf) |
看 DNS 回程是否也被导到 tailscale0:
1 | ip route get "$DNS" |
重点看 dev tailscale0。如果 DNS 不在管理网段内,并且也走了 tailscale0,可以单独保护 DNS IP:
1 | ip rule add to "$DNS"/32 pref 91 lookup main |
再验证:
1 | ip route get "$DNS" |
持久化配置
可以把规则写进 /etc/rc.local:
1 | cat >/etc/rc.local <<'EOF' |
再创建 rc-local.service:
1 | cat >/etc/systemd/system/rc-local.service <<'EOF' |
检查规则是否生效:
1 | ip rule |
防止把自己锁外面
测试 Tailscale 前,可以先放一个自动恢复:
1 | nohup sh -c 'sleep 90; tailscale down' >/tmp/ts-rescue.log 2>&1 & |
如果 90 秒内 SSH 没断,或者已经确认规则没问题,可以忽略它;如果 SSH 被断开,Tailscale 会在 90 秒后自动关闭,方便重新登录。
也可以开两个 SSH 窗口:一个执行 Tailscale 操作,一个专门观察路由和连接状态。
排查清单
完整顺序可以固定成下面这几步:
1 | # 1. 先确认 SSH 客户端 IP |
一句话总结:启动 Tailscale 后 SSH 断连,先查 ip route get <ssh_client_ip>。只要回程落到 tailscale0,就优先怀疑 Tailscale 的 table 52 抢了管理网段路由。