记一次 ZeroTier + Tailscale 双开导致内网穿透失败的排查

2026年03月30日7 次阅读0 人喜欢
NAS运维踩坑记录网络调试ZeroTierTailscaleMTU

记一次 ZeroTier + Tailscale 双开导致内网穿透失败的排查

背景

我在家里的 NAS 上同时跑了两个内网穿透工具:ZeroTierTailscale。平时用 ZeroTier 访问家里局域网的服务,一切正常。

直到有一天,我在南京的台式机(Windows)上通过 ZeroTier 访问马鞍山家里的 NAS,发现:ping 得通,但网页打不开。

折腾了一晚上,最后发现原因出乎意料。记录一下排查过程,也顺便介绍一下这两个工具。


先认识一下两位选手

ZeroTier

ZeroTier 是一个 P2P 虚拟组网工具。简单说,它能把世界上任意地方的设备组成一个虚拟局域网,每台设备拿到一个虚拟 IP(比如 192.168.80.x),然后就像在同一个局域网里一样互相访问。

工作原理:

  • 每个节点安装 ZeroTier 客户端,加入同一个 Network ID
  • 节点之间尝试 UDP 打洞(Hole Punching),建立 P2P 直连
  • 打洞失败的话,通过 PLANET 服务器(ZeroTier 官方的根服务器)中继转发
  • 你也可以自建 Moon 节点,作为更近的中继/打洞辅助

优点:

  • 免费版支持 25 台设备
  • 配置简单,装上就能用
  • 支持自建 Moon,国内访问更快

缺点:

  • NAT 打洞成功率取决于网络环境
  • 国内连接官方 PLANET 服务器延迟较高

Tailscale

Tailscale 是另一个 P2P 虚拟组网工具,基于 WireGuard 协议。原理类似,但实现方式不同。

工作原理:

  • 基于 WireGuard 加密隧道
  • 通过 Tailscale 的 协调服务器 交换密钥和路由信息
  • 节点之间尝试直连(UDP 打洞)
  • 直连失败时,通过 DERP 中继服务器转发(全球有几十个节点)

优点:

  • 基于 WireGuard,安全性高
  • 配置极其简单
  • DERP 中继全球分布,延迟尚可

缺点:

  • 免费版只有 100 台设备(个人够用)
  • DERP 中继带宽有限
  • 主要面向海外用户,国内 DERP 延迟较高

两者的核心区别

特性 ZeroTier Tailscale
协议 自有协议 (VL1/VL2) WireGuard
中继 PLANET 服务器 / 自建 Moon DERP 服务器
虚拟 IP 自定义网段(如 192.168.80.x) 固定 100.x.x.x 段
组网方式 加入同一 Network ID 登录同一账号
NAT 打洞 UDP 打洞 UDP 打洞 + DERP
开源 部分开源

什么是 MTU?

在讲排查过程之前,必须先解释一个关键概念:MTU

MTU 是什么

MTU(Maximum Transmission Unit,最大传输单元)是指一条网络链路上能传输的单个数据包的最大字节数

打个比方:网络传输就像用卡车运货。

  • MTU 就是卡车的载重量
  • 你要运 10 吨货,卡车载重 5 吨,就需要跑两趟
  • 如果卡车司机不知道路有限高(MTU 被限制),硬要装 10 吨,车就翻了(数据包被丢弃)

常见的 MTU 值

  • 普通以太网:MTU = 1500 字节(最常见)
  • PPPoE 拨号:MTU = 1492 字节(比以太网少了 8 字节 PPPoE 头)
  • ZeroTier 虚拟网卡:MTU = 2800 字节(ZeroTier 默认设的,因为它觉得虚拟网络不需要限制)
  • Tailscale:MTU = 1280 字节(保守设置,兼容性好)

MTU 不匹配会怎样?

当网络路径上某一段的 MTU 比你的数据包还小时:

  1. 正常情况:中间的路由器会把大包切成小包(分片,Fragmentation),到了目的地再组装
  2. DF 位设置了:现代操作系统默认设置 "Don't Fragment"(不分片)标志。路由器收到大包时,不会分片,而是丢弃,同时返回一个 ICMP 消息说"包太大了"
  3. ICMP 被防火墙拦截:很多防火墙会拦截 ICMP 消息。发送端永远收不到"包太大"的通知,继续发大包,全部被丢弃

这就是 PMTUD(Path MTU Discovery)失败 的经典场景。

表现就是:小包能通(比如 ping),大包不行(比如网页)


排查过程

第一步:确认现象

在南京的台式机(ZeroTier 分配的 IP 是 192.168.80.4,Windows 系统)上:

复制代码
C:\> ping 192.168.80.80
Reply from 192.168.80.80: bytes=32 time=429ms TTL=128

ping 通了,但浏览器打开 http://192.168.80.80 一直转圈,最终超时。

第二步:在 NAS 上检查服务状态

SSH 登录马鞍山的 NAS(192.168.80.80),检查 Web 服务是否正常:

bash 复制代码
# Nginx 确实在监听 80 和 443 端口
ss -tlnp | grep -E ':(80|443)\s'
LISTEN 0  511  0.0.0.0:80   0.0.0.0:*  users:(("nginx",...))
LISTEN 0  511  0.0.0.0:443  0.0.0.0:*  users:(("nginx",...))

服务没问题。在 NAS 上本地访问也没问题:

bash 复制代码
curl -sI http://192.168.80.80
HTTP/1.1 302 Moved Temporarily  # 正常响应

说明问题出在网络传输层面,不是 Web 服务本身。

第三步:检查防火墙

bash 复制代码
# iptables INPUT 链
iptables -L INPUT -n
Chain INPUT (policy ACCEPT)
# 没有拦截规则

防火墙也是放行的。

第四步:测试不同大小的数据包

这一步是关键突破。我用 ping 的 -s 参数指定不同的载荷大小:

bash 复制代码
# 从马鞍山 NAS (192.168.80.80) ping 南京台式机 (192.168.80.4)

# 56 字节 - 默认大小
ping -c 1 192.168.80.4
# ✅ 通了,429ms

# 1000 字节
ping -c 1 -M do -s 1000 192.168.80.4
# ✅ 通了,385ms

# 1100 字节
ping -c 1 -M do -s 1100 192.168.80.4
# ✅ 通了

# 1200 字节
ping -c 1 -M do -s 1200 192.168.80.4
# ❌ 100% 丢包!

# 1400 字节
ping -c 1 -M do -s 1400 192.168.80.4
# ❌ 100% 丢包!

-M do 表示设置 DF(Don't Fragment)位,禁止分片。

结论:这条路径的 MTU 上限在 1100~1200 字节之间。

而 ZeroTier 虚拟网卡的 MTU 设的是 2800 字节:

bash 复制代码
ip link show ztuze3h6cc
6: ztuze3h6cc: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2800 ...

HTTP 的 TCP 分段通常是 1460 字节,远超 1100 字节的路径限制。数据包在路上被丢了,TCP 握手能成功(因为 SYN 包很小),但传数据时大包过不去。

浏览器表现为:连接建立了,但一直在等待数据,最终超时。

第五步:找到真正的连接路径

到这里我知道是 MTU 的问题了,但还有一个疑问:为什么路径 MTU 这么低?

查看 ZeroTier 的节点连接状态:

bash 复制代码
zerotier-cli peers
<ztaddr>     <role>  <lat>  <link>   <path>
08702da864   MOON    13ms   DIRECT   124.222.237.219/42988
e8387325e3   LEAF    782ms  DIRECT   fd7a:115c:a1e0::283b:ba3e/9993

公司电脑(e8387325e3)显示延迟 782ms,路径是 fd7a:115c:a1e0::283b:ba3e

看到这个 IP 地址我愣了一下。fd7a:115c:a1e0::/48 这个前缀很眼熟——这不是 Tailscale 的私有 IPv6 地址段 吗?

再看公司电脑上的网络配置:

复制代码
未知适配器 Tailscale:
  IPv6 地址 . . . . . . . . . . . . : fd7a:115c:a1e0::283b:ba3e
  IPv4 地址 . . . . . . . . . . . . : 100.126.186.62

破案了。 公司电脑上同时跑了 Tailscale,ZeroTier 把 Tailscale 的地址当成了可用的网络路径。

实际的数据传输路径是这样的:

复制代码
公司电脑 (192.168.80.4)
  │
  ├→ ZeroTier 封装 (UDP 9993)
  │
  ├→ Tailscale 虚拟网卡 (fd7a:115c:a1e0::283b:ba3e)
  │
  ├→ Tailscale DERP 中继 (旧金山 sfo 节点, ~400ms)
  │
  └→ 到达 NAS (192.168.80.80)

双重隧道套娃! ZeroTier 隧道套在 Tailscale DERP 中继里面。

所以:

  • 延迟高达 782ms(Tailscale DERP 旧金山中继 400ms + ZeroTier 额外开销)
  • 路径 MTU 被 Tailscale 限制(Tailscale 的虚拟网卡 MTU 只有 1280 字节,再套上 ZeroTier 封装,实际可用更小)
  • HTTP 大包过不去

第六步:为什么以前没有这个问题?

在没有自建 Moon 之前,公司电脑和 NAS 之间的连接是这样的:

复制代码
公司电脑 → PLANET 服务器(公网中继) → NAS

走的是 ZeroTier 官方 PLANET 服务器中继。延迟高一点(~200ms),但路径 MTU 是正常的 1500 字节,HTTP 能正常工作。

自建 Moon 之后,ZeroTier 优先选择直连(DIRECT)而不是中继(RELAY)。它发现了 Tailscale 这条"直连"路径,就走这边了。虽然延迟更高、MTU 更低,但 ZeroTier 的逻辑是 DIRECT > RELAY,所以它觉得这是更好的路径。

再看一个对比:

我后来在公司的 Mac 笔记本上做了对比测试,Tailscale 和 ZeroTier 同时开着,完全没问题。原因是公司网络环境的 NAT 类型友好,ZeroTier 能成功打洞直连,不需要走 Tailscale。

而南京的台式机没有公网 IPv4,NAT 类型是对称型(Symmetric NAT),打洞成功率低。ZeroTier 打洞失败后,发现了 Tailscale 的地址,就走这条路了。


解决方案

临时方案:调整 MTU

在 NAS 上降低 ZeroTier 虚拟网卡的 MTU:

bash 复制代码
# 临时生效
ip link set ztuze3h6cc mtu 1100

但这只是治标,而且需要两端都改。公司电脑那边是 Windows,改 MTU 比较麻烦。

治本方案

核心思路:让公司电脑的 ZeroTier 能成功直连 NAS,不需要走 Tailscale。

NAS 有公网 IP(124.112.181.254),关键在于公司电脑那边的 NAT 打洞能不能成功。

方案 1:公司电脑的路由器开启 UPnP

UPnP 允许内网设备自动在路由器上创建端口映射。ZeroTier 支持 UPnP/NAT-PMP,开启后打洞成功率会大幅提升。

方案 2:手动端口转发

在公司路由器上设置端口转发,把 UDP 9993 转发到公司电脑的内网 IP。

方案 3:临时关闭 Tailscale 测试

在公司电脑上运行 tailscale down,然后观察 ZeroTier 能不能通过 PLANET 自动建立连接:

powershell 复制代码
tailscale down
# 等几分钟,然后检查
zerotier-cli peers

如果 ZeroTier 能找到其他路径(比如通过 Moon 中继或直接打洞),说明问题就是 Tailscale 干扰的。


总结

问题 原因
ping 通但网页打不开 路径 MTU 不匹配,大包被丢弃
路径 MTU 为什么低 ZeroTier 隧道套在 Tailscale DERP 中继里面
为什么走 Tailscale 公司电脑没有公网 IP,NAT 打洞失败,Tailscale 是唯一可用的"直连"路径
为什么以前没问题 没有 Moon 时走 PLANET 中继,MTU 正常

教训: 两个穿透工具同时运行时,要注意它们之间可能互相"抢路"。如果其中一个提供了"直连"路径(即使这个路径质量很差),另一个可能会优先选择它而不是走正常的中继。


排查环境:NAS (Debian, ZeroTier 1.14.2) + 公司电脑 (Windows 11, ZeroTier 1.16.0, Tailscale)

加载评论中...