MagicTools
openclawMarch 3, 2026227 views

Tailscale 导致服务器外网断连的排查与修复

一、问题描述

在一台 Ubuntu 22.04 云服务器(阿里云/类似 VPC 环境)上安装 Tailscale 后,发现服务器无法访问外网:

  • ping www.baidu.com → Temporary failure in name resolution
  • ping 8.8.8.8 → 100% 丢包
  • 应用服务中所有依赖外网的请求全部超时

现象看起来像是"网络彻底断了",实际上问题远比这微妙。


二、系统环境

┌──────────┬────────────────────────────────────────────────────────┐ │ 项目 │ 详情 │ ├──────────┼────────────────────────────────────────────────────────┤ │ OS │ Ubuntu 22.04 LTS (5.15.0-100-generic) │ ├──────────┼────────────────────────────────────────────────────────┤ │ 网络接口 │ eth0 (172.31.0.2/20), tailscale0 (100.90.187.69/32) │ ├──────────┼────────────────────────────────────────────────────────┤ │ 云环境 │ 内网网段 172.31.0.0/20,内部 DNS 100.96.0.2/100.96.0.3 │ ├──────────┼────────────────────────────────────────────────────────┤ │ 防火墙 │ nftables(Tailscale 自动注入规则) │ └──────────┴────────────────────────────────────────────────────────┘


三、排查过程

第一步:收集基础信息

首先全面收集网络现状,避免盲目猜测:

查看路由表

ip route show

查看 DNS 配置

cat /etc/resolv.conf

查看 Tailscale 状态

tailscale status

测试外网连通性

ping -c 2 www.baidu.com ping -c 2 8.8.8.8

关键发现 1:/etc/resolv.conf 已被 Tailscale 接管:

resolv.conf(5) file generated by tailscale

DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN

nameserver 100.100.100.100 search tailaca6af.ts.net

关键发现 2:ping 8.8.8.8 100% 丢包,第一感觉是"IP 层就不通了"。


第二步:区分 ICMP 失败 vs 真实断网

ping 失败不一定代表网络不通,很多云厂商的安全组默认屏蔽 ICMP。用 TCP 验证真实连通性:

用 TCP 测试 8.8.8.8:53

nc -zv 8.8.8.8 53

用 curl 测试 HTTP

curl -v --max-time 5 http://8.8.8.8

关键发现 3:nc -zv 8.8.8.8 53 成功! TCP 连通性完全正常。

结论:外网 IP 层没问题,ping 丢包是云厂商防火墙屏蔽 ICMP 的假象。真正的问题只是 DNS 解析失败。


第三步:定位 DNS 失败根因

测试 Tailscale DNS 是否可达

nc -zv 100.100.100.100 53 # TCP:成功 dig @100.100.100.100 www.baidu.com +time=3 # UDP:全部超时!

关键发现 4:Tailscale 的 MagicDNS(100.100.100.100)TCP 53 可连,但 UDP 53 全部超时,说明 DNS 代理本身工作异常。

禁用 Tailscale DNS 接管后,系统恢复使用 DHCP 下发的 DNS 100.96.0.2 / 100.96.0.3,但问题依旧:

dig @100.96.0.2 www.baidu.com +time=3

;; communications error: timed out(同样超时)


第四步:找到真正的幕后黑手

查看 Tailscale 注入的 nftables 防火墙规则:

nft list ruleset

发现这条关键规则:

chain ts-input { ... iifname != "tailscale0" ip saddr 100.64.0.0/10 counter drop ... }

翻译:凡是从非 tailscale0 接口进来、且源 IP 属于 100.64.0.0/10 网段的包,全部丢弃。

这是 Tailscale 为了防止 CGNAT IP 欺骗而设计的安全规则。但问题在于——

云厂商内部 DNS:100.96.0.2 / 100.96.0.3 CGNAT 网段: 100.64.0.0/10(范围:100.64.0.0 ~ 100.127.255.255)

100.96.0.x 恰好落在这个段内!

整个问题的完整链路如下:

[本机发出 DNS 查询 UDP] ↓ [100.96.0.2 收到查询,通过 eth0 回包] ↓ [回包源 IP = 100.96.0.2,属于 100.64.0.0/10] ↓ [nftables ts-input 规则:非 tailscale0 入口 + CGNAT 源IP → DROP] ↓ [DNS 响应被丢弃 → 查询超时 → 所有域名解析失败]

Tailscale 的 MagicDNS 代理(100.100.100.100)也是同理,它在内部尝试使用这些 DNS 时同样被自己的规则拦截,导致 UDP 不通。


四、解决方案

既然云厂商内部 DNS 的 IP 段与 Tailscale 防护规则冲突,最简洁的修复是:禁用 Tailscale 接管 DNS,改用不在 CGNAT 段的公共 DNS。

步骤 1:禁用 Tailscale DNS 接管

tailscale set --accept-dns=false

执行后 Tailscale 释放对 /etc/resolv.conf 的控制,交还给 systemd-resolved。

步骤 2:配置公共 DNS

备份原始配置

cp /etc/systemd/resolved.conf /etc/systemd/resolved.conf.bak

写入新配置

cat > /etc/systemd/resolved.conf << 'EOF' [Resolve] DNS=114.114.114.114 8.8.8.8 FallbackDNS=8.8.4.4 223.5.5.5 LLMNR=no MulticastDNS=no DNSSEC=no Cache=yes DNSStubListener=yes ReadEtcHosts=yes EOF

重启 systemd-resolved

systemctl restart systemd-resolved

步骤 3:验证修复

dig www.baidu.com A +short

180.101.49.44 ✓

curl -o /dev/null -w '%{http_code}\n' http://www.baidu.com

200 ✓

curl -o /dev/null -w '%{http_code}\n' https://github.com

200 ✓

tailscale status

100.90.187.69 online ✓

外网恢复正常,Tailscale 网络连接不受影响。


五、经验总结

  1. ping 失败 ≠ 网络断了

云服务器环境下,安全组默认屏蔽 ICMP。排查时应优先用 TCP 测试连通性(nc -zv、curl),避免被 ping 的假阴性误导,浪费时间排查根本不存在的路由问题。

  1. 安装网络工具前,了解它改了什么

Tailscale 安装后会自动做三件事,需要提前知晓:

  • 接管 /etc/resolv.conf,使用自己的 MagicDNS
  • 注入 nftables/iptables 规则,包括 DROP CGNAT 入包的安全规则
  • 添加 policy routing(ip rule + 路由表 52)

在 CGNAT 内网 DNS 环境(如阿里云、腾讯云 VPC)中,这会产生隐性冲突。

  1. CGNAT 段 100.64.0.0/10 是个陷阱

这个段(100.64.0.0 ~ 100.127.255.255)同时被用于:

  • IETF RFC 6598:运营商级 NAT 共享地址
  • Tailscale:节点 IP 分配(100.x.x.x)
  • 部分云厂商:VPC 内部服务 IP(DNS、NTP、元数据等)

三者共用同一地址段,极易发生安全规则误判。在这类环境下使用 Tailscale,务必检查云厂商内部服务 IP 是否落在该段。

  1. 诊断优先,修复靠后

本次排查经历了以下层层递进:

表象:ping 失败(误以为路由断了) ↓ 发现:TCP 8.8.8.8:53 可通(路由其实正常) ↓ 缩小:DNS 解析失败(问题定位到 DNS 层) ↓ 深挖:100.96.0.x 响应包被 nftables DROP(找到根因) ↓ 修复:换用公共 DNS 绕开冲突(一次成功)

每一步都基于证据推进,没有盲目修改配置。如果一开始就跟着感觉乱改路由或重装 Tailscale,不仅浪费时间,还可能让问题更复杂。

  1. 快速修复备忘

遇到同样问题,三步解决:

1. 禁用 Tailscale DNS 接管

tailscale set --accept-dns=false

2. 配置公共 DNS(国内推荐 114/阿里,国际推荐 8.8.8.8)

echo -e "[Resolve]\nDNS=114.114.114.114 8.8.8.8\nFallbackDNS=223.5.5.5 8.8.4.4"
>> /etc/systemd/resolved.conf systemctl restart systemd-resolved

3. 验证

curl -o /dev/null -w '%{http_code}\n' http://www.baidu.com


环境说明:本文排查过程基于 Ubuntu 22.04 + 阿里云 VPC 环境,其他使用 VPC 内部 DNS 的云厂商(腾讯云、华为云等)若 DNS IP 落在 100.64.0.0/10 段,均可能遇到相同问题。

======


我们DNS地址换成原来的会影响tailscale的功能吗? 是不是也可以让阿里云官方的IP放到可通行的列表或者直接让 tailscale的DNS服务器不禁止ip地址 是不是也可以

⏺ 很好的问题,三个思路都值得分析。

问题一:当前方案是否影响 Tailscale 功能? ️

有一点轻微影响:禁用了 MagicDNS。

┌───────────────────────────────────────────────────────────────┬─────────────┐ │ 功能 │ 影响 │ ├───────────────────────────────────────────────────────────────┼─────────────┤ │ Tailscale 节点间互通(IP 访问) │ ✅ 完全正常 │ ├───────────────────────────────────────────────────────────────┼─────────────┤ │ 流量加密/隧道 │ ✅ 完全正常 │ ├───────────────────────────────────────────────────────────────┼─────────────┤ │ 通过 Tailscale 主机名访问节点(如 machine.tailaca6af.ts.net) │ ❌ 无法解析 │ └───────────────────────────────────────────────────────────────┴─────────────┘

如果你只是用 Tailscale 做 IP 层的内网互联,当前方案没有任何影响。


问题二/三:另外两种修复思路

方案 A:在 nftables 白名单中放行阿里云 DNS IP

原理:在 Tailscale 的 DROP 规则之前,插入一条 ACCEPT 规则:

放行阿里云 DNS 响应包(100.96.0.2 / 100.96.0.3)

nft insert rule ip filter ts-input
iifname != "tailscale0" ip saddr { 100.96.0.2, 100.96.0.3 } accept

致命问题:Tailscale 每次重启都会重建自己的 nftables 链,你插入的规则会被清除。

要让它持久化,需要用 systemd 钩子在 Tailscale 启动后重新注入:

/etc/systemd/system/tailscale-dns-whitelist.service

[Unit] Description=Whitelist Aliyun DNS after Tailscale starts After=tailscaled.service Requires=tailscaled.service

[Service] Type=oneshot ExecStart=/usr/sbin/nft insert rule ip filter ts-input
iifname != "tailscale0" ip saddr { 100.96.0.2, 100.96.0.3 } accept RemainAfterExit=yes

[Install] WantedBy=multi-user.target

缺点:维护成本高,Tailscale 大版本升级后规则结构可能变化,需要重新调整。


方案 B:让 Tailscale 自己的 DNS 代理正确转发(最优解)

原理:不绕开 Tailscale DNS,而是让 Tailscale 使用不在 CGNAT 段的公共 DNS 作为上游,同时保留 MagicDNS 功能。

启用 Tailscale DNS 接管,但指定上游 DNS 为公共服务器

tailscale set --accept-dns=true

在 Tailscale 管理后台 (admin.tailscale.com) → DNS 设置中

配置 Global nameservers 为 114.114.114.114 / 8.8.8.8

这样:

  • Tailscale MagicDNS 继续工作(.ts.net 主机名可解析)
  • 上游 DNS 查询走 114.114.114.114(不在 CGNAT 段,不触发 DROP 规则)
  • 无需改动 nftables

三种方案对比

┌──────────────────────────────────┬──────────┬───────────────────┬──────────┬────────────────────────┐ │ 方案 │ MagicDNS │ 持久性 │ 维护成本 │ 推荐 │ ├──────────────────────────────────┼──────────┼───────────────────┼──────────┼────────────────────────┤ │ 当前:公共DNS + accept-dns=false │ ❌ │ ✅ │ 低 │ 适合不需要主机名的场景 │ ├──────────────────────────────────┼──────────┼───────────────────┼──────────┼────────────────────────┤ │ nftables 白名单 │ ✅ │ 需要 systemd 钩子 │ 高 │ 不推荐 │ ├──────────────────────────────────┼──────────┼───────────────────┼──────────┼────────────────────────┤ │ Tailscale 后台配置上游 DNS │ ✅ │ ✅ │ 低 │ 推荐(功能最完整) │ └──────────────────────────────────┴──────────┴───────────────────┴──────────┴────────────────────────┘


建议

如果你的服务器需要用 Tailscale 主机名互相访问,执行方案 B:

重新启用 Tailscale DNS 接管

tailscale set --accept-dns=true

然后去 https://login.tailscale.com/admin/dns → DNS → Add nameserver → 填入 114.114.114.114,保存后 Tailscale 会把这个公共 DNS 下发给所有节点作为上游,问题根源彻底解决,MagicDNS 也恢复工作。

Published by MagicTools