tailscale up 默认 --accept-dns=true。文档把 MagicDNS 描述为一个便利功能——用短名字而不是 IP 来访问 Tailscale 节点。每篇 Tailscale 安装指南都把它当作无害的。在笔记本上,确实无害。在服务器上,它会把你唯一的 DNS 解析器替换成一个用户态转发器,开机时还没就绪,公网查询还会间歇性失败。
TL;DR: MagicDNS 悄悄把 /etc/resolv.conf 改写为 100.100.100.100。在服务器上,这会导致公网域名间歇性 SERVFAIL 和重启后的崩溃循环。修复:关闭 DNS 接管,手动配置解析器。
症状 #
几台用 Tailscale 组网的 Linux 服务器出现了诡异行为:
- 出站请求随机超时,等 2-3 秒后返回错误
- 刷新一下又好了;故障反复出现,毫无规律
- 服务日志里散落着
SERVFAIL和i/o timeout - 重启后,多个服务同时启动失败,全部报 DNS 解析失败
如果是网络故障,所有请求都会失败。如果是应用 bug,重启不会同时打垮多个无关服务。指向更根本的东西——DNS。
检查 resolv.conf #
在出问题的服务器上:
cat /etc/resolv.conf
# resolv.conf(5) file generated by tailscale
# For more info, see https://tailscale.com/s/resolvconf-overwrite
# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN
nameserver 100.100.100.100
search your-tailnet.ts.net
看到 100.100.100.100 和 Tailscale 注释头——就是它。MagicDNS 默认开启。它接管 /etc/resolv.conf,把 Tailscale 内置转发器变成整个系统唯一的 DNS 解析器。所有 DNS 查询——应用解析 api.example.com、apt 检查 security.debian.org——全部经过它。
# 确认 MagicDNS 是否激活
tailscale debug prefs 2>/dev/null | grep CorpDNS
"CorpDNS": true 就是确认了。
转发器不可靠 #
MagicDNS 是为客户端设备设计的。在服务器上作为唯一解析器,它会对完全正常的公网域名间歇性返回 SERVFAIL:
# 检查过去 24 小时的 DNS 故障(以 root 运行)
journalctl --since "24 hours ago" | grep -i "SERVFAIL\|server misbehaving\|i/o timeout.*:53"
看到了这些:
ERROR lookup app.example.com: (exchange6: SERVFAIL | exchange4: SERVFAIL) [2.17s]
ERROR lookup app.example.com: (exchange6: SERVFAIL | exchange4: SERVFAIL) [2.25s]
ERROR lookup cdn.example.com: (exchange4: SERVFAIL | exchange6: SERVFAIL) [2.16s]
多个公网域名同时失败,每次耗时 2 秒以上。这些域名跟 Tailscale 毫无关系——纯粹是把所有流量路由到 MagicDNS 的附带伤害。
重启竞态条件 #
最严重的故障模式。从一次供应商维护重启后的 journalctl 还原的时间线:
21:58:44 System boots, tailscaled starts
21:58:44 resolv.conf overwritten → nameserver 100.100.100.100
21:58:44 Other services begin starting
21:58:55 Service A starts, attempts DNS:
ERR lookup app.example.com on 100.100.100.100:53: i/o timeout
21:59:00 ERR: server misbehaving → Service A crashes
21:59:05 systemd restarts Service A → DNS fails again → crash
21:59:11 systemd restarts again → DNS fails → crash
... (every 5 seconds for 5 minutes)
tailscaled 启动后立刻写 resolv.conf,但 MagicDNS 转发器需要时间初始化——连接 Tailscale 控制面、获取配置、建立上游 DNS。在这个窗口期,100.100.100.100 已经写进了 resolv.conf,但什么都解析不了。在这个间隙启动的每个服务都会进入崩溃循环。
根因 #
MagicDNS 是为客户端设备设计的——笔记本、手机。偶尔 DNS 抖动在那里无感。
在服务器上作为唯一解析器,设计假设全部失效:
- 单点故障:所有 DNS 依赖一个用户态进程。崩溃或未就绪 → 全部 DNS 中断
- 间歇性不可靠:公网查询偶尔 SERVFAIL——很难追溯到 DNS 层
- 重启竞态条件:resolv.conf 指向 Tailscale,但 Tailscale 还没准备好
- 静默接管:
tailscale up默认--accept-dns=true,没有任何提示
resolv.conf 指向 1.1.1.1 或 8.8.8.8 时,可用性高得多。即使 Tailscale 整个崩溃,DNS 仍然正常。
修复 #
在服务器上关闭 MagicDNS(以 root 运行):
tailscale set --accept-dns=false
然后配置你自己的 DNS。对于没有 systemd-resolved 的系统:
cat > /etc/resolv.conf << 'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF
对于运行 systemd-resolved 的系统,通过 /etc/systemd/resolved.conf 配置——直接写 /etc/resolv.conf 会被覆盖。
防止 resolv.conf 被其他进程改写:
chattr +i /etc/resolv.conf
注意:chattr +i 在 OpenVZ 7 容器上可能因文件系统限制而不生效。这类系统上还需检查供应商的 DHCP 客户端是否也在覆盖 resolv.conf。
验证 #
# DNS 不再经过 Tailscale
cat /etc/resolv.conf # 应显示 1.1.1.1,不是 100.100.100.100
dig +short google.com # 应秒回
# Tailscale 本身不受影响
tailscale status
tailscale ping <other-node>
--accept-dns=false 跨重启持久生效。
你会失去什么 #
| 功能 | 是否受影响 |
|---|---|
| Tailscale 组网 | 不受影响 |
| 通过 Tailscale SSH 到这台服务器 | 不受影响 |
tailscale status / tailscale ping | 不受影响 |
| 所有应用的出站 DNS | 不受影响(现在走 1.1.1.1) |
| 在这台服务器上用短名字访问 Tailscale 节点 | 需改用 IP |
对服务器来说,最后一项几乎用不到。如果确实需要,往 /etc/hosts 里加条目即可。
快速自检 #
grep -c "100.100.100.100" /etc/resolv.conf
返回 1?你在用 MagicDNS。检查是否已经在造成损害:
journalctl --since "24 hours ago" --no-pager | grep -c "SERVFAIL\|server misbehaving"
非零就说明 MagicDNS 已经在影响你的服务。
Docker 用户 #
容器会根据网络模式继承宿主机坏掉的 DNS:
| 配置 | 风险 |
|---|---|
bridge + 显式 dns: [1.1.1.1] | 安全 |
| bridge + 默认 DNS | 可能继承宿主机 DNS |
| host 网络 | 完全暴露 |
# 检查所有运行中的容器(以 root 运行)
docker inspect --format '{{.Name}} dns={{.HostConfig.Dns}} net={{.HostConfig.NetworkMode}}' \
$(docker ps -q)
所有服务器上的 MagicDNS 都已关闭。两周,零 DNS 相关故障。之前平均每周两三次——只是一直没把它们跟 Tailscale 联系起来。