ping 通了但 SSH 连不上:一次 Tailscale SSH 超时排查

2026年8月2日| 更新于 2026年8月30日| Ruichen Zhou| 约 9 分钟阅读

家里的 mac-mini 需要 SSH 到各地的设备。有一天,它能稳定 ping 到 vps-hk,却无法建立 SSH 连接。

ICMP 往返正常,TCP 端口也能返回 OpenSSH 版本信息,但 SSH 停在了随后的密钥交换阶段。下面按当时的检查顺序说明每一步看到了什么,以及最后怎样恢复使用。

2026-08-03 更正:早期版本有两处不准确:把 MappingVariesByDestIP: true 直接写成“已经确认是 Symmetric NAT”,又用非同时采集的连接状态推断方向性故障。正文已经改正,解释见对应小节。

先确认 SSH 卡在哪里

从 mac-mini 访问 vps-hk 的 Tailscale 地址 100.100.1.2

ping 100.100.1.2

当时 ICMP 可达,但具体的包数、TTL 和延迟没有可信记录,这里不写。SSH 则连续 10 次超时:

$ ssh vps-hk
Connection to 100.100.1.2 port 22022 timed out

nc 连接同一个端口,可以收到服务端的版本信息:

$ nc 100.100.1.2 22022
SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u10

这说明 TCP 连接已经建立,服务端也发回了数据。继续用 ssh -vv 查看 SSH 握手:

$ ssh -vv vps-hk
...
debug1: kex: algorithm: ecdh-sha2-nistp256
debug1: kex: host key algorithm: ssh-ed25519
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
Connection to 100.100.1.2 port 22022 timed out

问题由此缩小到 banner 之后的密钥交换阶段;至于回复是否发出、丢在哪一段,仅凭客户端日志判断不了。

MTU 没有留下可用结果

SSH 握手超时可能与 MTU 有关。这类检查的顺序是:先查看 Tailscale 接口的 MTU 是否异常,再从小 payload 开始递增,测试不分片的 ICMP 包能否往返。

这次没有留下接口 MTU 数值和递增测试的可信结果,因此 MTU 是否参与了这次超时无法判断,结论停在这里。

本机代理没有接管 Tailnet 地址

mac-mini 同时运行 SFM(sing-box 图形客户端)。如果系统代理接管了 100.64.0.0/10,Tailscale 流量可能走错接口。

路由表显示 Tailscale 地址走 utun4,SFM 的默认流量走 utun5

100.64/10          utun4              USc      utun4     # Tailscale
default            link#26            UCSg     utun5     # SFM

SFM 的规则也排除了 Tailnet 地址。现有配置没有显示这次 SSH 流量经过 SFM,因此没有修改代理规则。

两端当时显示了不同的连接方式

mac-mini 的 tailscale status 显示到 vps-hk 为直连:

$ tailscale status
100.100.1.2   vps-hk   active; direct <vps-public-ip>:41641, tx 85092 rx 32764

vps-hk 上的检查却显示到 mac-mini 仍经香港的 DERP 中继:

$ tailscale ping 100.100.1.4
pong from mac-mini (100.100.1.4) via DERP(hkg) in 342ms
direct connection not established

两个命令不是同时执行的,Tailscale 又会在直连与中继之间切换,所以这里只能说明采样时 vps-hk 一侧还没建立直连。

MappingVariesByDestIP 说明什么

两端是否容易直连,还与 NAT 怎样分配公网端口有关。运行:

$ tailscale netcheck
* UDP: true
* MappingVariesByDestIP: true
* Nearest DERP: Hong Kong

MappingVariesByDestIP: true 表示,同一台设备访问不同目标 IP 时,NAT 映射可能不同。对端从一个探测服务器看到的端口,不一定能用于建立另一条点对点连接,这会增加 UDP 打洞的难度。

但这个字段不能单独判定 NAT 类型,也不能证明超时由 NAT 造成。要定位 KEX_ECDH_REPLY 丢在哪一段,需要在故障发生时两端同步抓包。这次没有留下这类数据,原因只能停在这里。

有公网地址的 VPS 改走公网 SSH

vps-hk 有公网地址,可以绕过当时不稳定的 Tailscale 连接。相同的 SSH 服务做了 10 次对照:

  • 100.100.1.2:22022:10 次全部超时;
  • <vps-public-ip>:22022:10 次全部成功,每次约 0.2 秒。

这个结果说明公网入口当时可用,可以先恢复管理。

原来的 SSH 配置只使用 Tailscale 地址:

Host vps-hk
  HostName 100.100.1.2
  User root
  Port 22022

修改后,日常别名使用公网地址,保留带 -ts 后缀的 Tailscale 入口:

Host vps-hk
  HostName <vps-public-ip>
  User root
  Port 22022

Host vps-hk-ts
  HostName 100.100.1.2
  User root
  Port 22022

配置由 chezmoi 同步到开发机。修改后,mac-mini 和 precision-7920 到两台 VPS 的 SSH 检查均为 5/5 成功。没有公网地址的 n1、cudy 和 mac-mini 仍使用 Tailscale。

没有公网入口的设备使用 Peer Relay 和 DERP

改走公网只适用于有公网地址的机器。访问家中没有公网地址的设备时,客户端仍先尝试直连;直连失败后可以使用 Peer Relay,再使用 DERP:

直连
  ↓ 失败
Peer Relay(自有 VPS)
  ↓ 不可用
DERP

两台 VPS 已启用 Peer Relay,并通过 tailnet policy 指定可以使用它的设备。配置方法见自建 Tailscale DERP 中继节点Peer Relay 官方文档

测试时目标连接短暂经过 DERP 后恢复了直连。能确认的是配置已下发,客户端发现了 relay 候选;Peer Relay 是否真正承载过业务流量,现有记录看不出来。

遇到同类问题时怎样检查

  1. ping 确认 ICMP 是否往返,再用 nc <地址> <端口> 检查 TCP 端口能否返回 banner。
  2. 运行 ssh -vv,记录超时前的最后一行。等待某条消息不等于服务端已经发出它。
  3. 使用系统支持的 DF 参数测试较大的 ICMP 包,排查常见 MTU 问题。
  4. 查看路由表,确认 100.64.0.0/10 走 Tailscale 接口,没有被本机代理接管。
  5. 运行 tailscale netcheck,记录 UDP、DERP 和 MappingVariesByDestIP
  6. 尽量同时在两端运行 tailscale statustailscale ping,确认当时显示 directpeer-relay 还是 DERP
  7. 故障还在发生时,在两端同时抓包或留日志;事后的状态快照无法替代抓包。
  8. VPS 有公网入口时,用相同的 SSH 端口做对照。公网可用可以先恢复管理。

评论