NNetpath
原理预计 35 分钟

Tailscale:WireGuard 网格与 NAT 穿透

同样是 WireGuard,为什么它不用你配任何 IP、开任何端口就能连上。

学完这节你能做到

  • 解释控制面与数据面分离的收益,说出协调服务器看不到什么
  • 说清 NAT 穿透失败时 DERP 中继接管的条件
  • 按需求选择 subnet router、exit node 还是逐机安装

建议先学跳过这几节会看不懂本节的部分推导

手工 WireGuard 的成本在哪

上一节的配置只有两个节点。加到 10 个节点、要两两直连呢?

每个节点要认识另外 9 个 peer
10 × 9 = 90 个隧道端点配置
新增 1 个节点 → 要改 10 台机器的配置

传统办法是退回中心辐射(hub-and-spoke):所有人连一台集中器。代价是绕路—— 纽约的客户端访问纽约的服务器,却要先跑一趟旧金山的集中器,延迟付两遍。

Tailscale 的解法是:把"交换配置"这件事自动化,把"传数据"这件事保持点对点。

控制面与数据面分开

        控制面(中心辐射,只传密钥和策略,几乎没有流量)
                    ┌──────────────────┐
                    │  协调服务器       │
                    └──┬────┬────┬─────┘
                       │    │    │
                    ┌──▼─┐┌─▼──┐┌▼───┐
                    │节点││节点││节点│
                    └──┬─┘└─┬──┘└┬───┘
                       └────┼────┘
        数据面(全互联网格,WireGuard 直连)

官方对这个设计的说法很直白:控制面是中心辐射的,但这不重要,因为它几乎不承载流量; 数据面才是网格。好处是处理能力随节点数一起增长,不存在集中器那样的吞吐天花板。

数据面用的是 WireGuard 的用户态实现(wireguard-go),所以不依赖内核模块, 容器和各种奇怪平台上都能跑。

密钥交换:一个公钥投递箱

协调服务器的角色,官方原话是"a shared drop box for public keys":

  1. 每个节点自己生成密钥对
  2. 上传公钥 + 当前能被访问到的地址 + 所属域
  3. 下载同域内其它节点的公钥和地址
  4. 用这些信息配置本地的 WireGuard

私钥永远不离开节点。 所以协调服务器看得到公钥、节点地址、域归属和 ACL 策略, 看不到私钥,因此也无法解密任何流量。

身份认证外包给 IdP(OAuth2 / OIDC / SAML,比如 Google Workspace、Entra ID)—— 它已经掌握了你的用户列表、密码和 2FA,不需要再维护第二套账号体系。

NAT 穿透:为什么不用 UPnP

节点在咖啡馆、在 4G、在层层 NAT 后面,两边都没有开放端口。

历史上的做法是 UPnP,而官方评价是它"很少能用,而且真能用的时候通常危险地好用, 直到管理员把它关掉"。Tailscale 走的是 STUN / ICE 那套标准技术, 在很多你以为不可能的场景下也能打通直连。

收益是不需要在防火墙上开任何入向端口——这本身就消掉了一大类人为配置错误。

DERP:打不通时的中继

有些网络直接封禁 UDP,STUN/ICE 无能为力。这时候 Tailscale 会退到 DERP (Designated Encrypted Relay for Packets):

特点说明
角色相当于 ICE 里的 TURN,但用 HTTPS 流 + WireGuard 密钥
触发条件兜底,直连打不通时才用
路由方式非对称:各自走离接收方最近的中继
能否解密不能 —— 私钥不离开节点,它只是转发已加密的字节
附带好处等于给 WireGuard 补上了它原生没有的 TCP 回退

这正好回答了上一节结尾的问题:纯 WireGuard 在 UDP 被封的网络里没救,Tailscale 有 DERP 兜底。

# 看每个 peer 是直连还是走中继
tailscale status
100.64.0.1   laptop     user@   linux   -
100.64.0.2   nas        user@   linux   idle, tx 1832 rx 2140
             ↑ 后面标 "direct 203.0.113.5:41641" 是直连
             ↑ 标 "relay \"tok\"" 就是在走 DERP

# NAT 类型与各中继延迟的体检
tailscale netcheck

# 测某个节点走的哪条路
tailscale ping nas
性能不对时先看是不是在走 DERP

中继会明显增加延迟。tailscale status 里如果某个 peer 一直标着 relay, 就该查为什么打不通直连:出口是不是封了 UDP、是不是对称 NAT、 或者干脆给其中一端开个公网端口(--advertise-exit-node 的机器尤其值得这么做)。

tailscale netcheck 会直接报告 UDP 是否可用、NAT 是否"hairpinning"、各 DERP 的 RTT, 比猜快得多。

ACL:中心定策略,每个节点自己执行

网格架构没有集中的卡点,那策略在哪执行?答案是"在每一个节点上": 每个节点在解密时就把不允许的入向连接丢掉。

还有一层更彻底的保护:协调服务器只会把"允许访问你"的那些节点的公钥发给你。 未获授权的机器连发起请求的资格都没有——官方的说法是"就像那些机器不存在一样"。

策略用 HuJSON 写,集中在协调服务器上维护:

{
  "tagOwners": {
    "tag:prod": ["group:sre"],
    "tag:ci":   ["group:sre"],
  },
  "acls": [
    // SRE 组可以访问生产机器的 SSH 与 K8s API
    { "action": "accept", "src": ["group:sre"], "dst": ["tag:prod:22,6443"] },
    // CI 只能访问镜像仓库
    { "action": "accept", "src": ["tag:ci"], "dst": ["tag:registry:443"] },
    // 其余默认拒绝
  ],
}

对比一下传统做法:规则写在集中器的防火墙上、以 IP 为单位、散落在多台设备上各配一遍。 这里是以身份为单位、写一次、自动分发

接入遗留网络:两个开关

不可能给所有设备都装客户端(打印机、老服务器、网络设备)。两个机制解决:

# 子网路由器:把一整个内网段接进 tailnet
tailscale up --advertise-routes=192.168.50.0/24,10.20.0.0/16
# 其它节点要显式接受
tailscale up --accept-routes

# 出口节点:把所有出网流量从这台机器发出去
tailscale up --advertise-exit-node
tailscale set --exit-node=<node>

两者都要在管理后台批准(避免任意节点自己宣告路由)。

!子网路由器是端到端加密的唯一例外

官方文档明确写了这一点:子网路由器要解密流量再转发进物理内网, 所以从子网路由器到内网设备的那一段是明文的。

这不是缺陷而是必然——内网里那台老设备不会说 WireGuard。但要意识到: 子网路由器是一个信任集中点,它的安全等级应该按网关来对待,而不是按普通节点。

什么时候用它,什么时候不用

需求建议
几台机器互联,成员基本不变自建 WireGuard 就够,别引入依赖
成员经常变、设备到处跑、都在 NAT 后Tailscale,省下的是持续的运维
要用现有 IdP 做认证与离职回收Tailscale / Pritunl
不接受控制面在第三方Headscale(开源的协调服务器实现)自建控制面
需要 OpenVPN 客户端兼容性、组织化管理与审计Pritunl(下一节)
极致吞吐、机器固定在机房自建内核态 WireGuard,用户态实现有额外开销

判断的核心不是性能,是你在为什么付代价:Tailscale 让你用一点控制权换掉大量密钥分发和 NAT 穿透的运维;自建则相反。

检查点

检查点单选

Tailscale 的协调服务器能看到什么?

检查点单选

tailscale status 显示某个节点一直标着 relay。这意味着什么?

检查点单选

关于 Tailscale 的 subnet router,下面哪个说法正确?

这节课的落点

  • 控制面中心辐射(只传密钥与策略),数据面全互联网格(WireGuard 直连)
  • 协调服务器是"公钥投递箱":私钥永不离开节点,所以它解不了流量
  • 认证外包给 IdP,不再维护第二套账号,离职回收走原有流程
  • NAT 穿透用 STUN/ICE 而不是 UPnP,不需要开放任何入向端口
  • DERP 是兜底中继:用 HTTPS + WireGuard 密钥,读不到内容,顺带补上 TCP 回退
  • ACL 中心定义、每个节点执行;未授权节点连公钥都拿不到
  • subnet routerexit node 接入遗留网络,但 subnet router 是端到端加密的例外
  • 排障三条命令:tailscale status(直连还是中继)、netcheck(NAT 与 DERP 体检)、ping
  • 不想把控制面交给第三方就用 Headscale 自建

延伸资料