跳到正文

目录

Tailscale 深度拆解:基于 WireGuard 的零配置 mesh VPN

Tailscale 深度拆解:基于 WireGuard 的零配置 mesh VPN

核心判断

Tailscale 的本质是把"VPN 配置管理"从命令行、IPSec PSK、证书系统升级为身份层。它把 WireGuard 当作"传输层",自己构建"控制面"(coordination server / login server)和身份层(Google / Microsoft / GitHub OAuth)。结果是:开发者不需要管理 PSK 和 CA,不需要懂 NAT 穿透原理,不需要暴露公网端口。这正是它能在 2020 年主仓库开源后迅速获得大量 DevOps、SRE 和远程办公用户的原因。

项目坐标

维度数据
仓库tailscale/tailscale
Stars约 3.6 万(2026-09)
主语言Go
LicenseBSD-3-Clause(客户端与服务端大部分代码开源)
商业关系Tailscale 公司维护;开源社区另有 Headscale 兼容控制面
核心依赖WireGuard(Linux 内核模块或用户态实现)+ 用户态 tun 设备

Tailscale 不是传统 VPN

传统 VPN(IPSec、OpenVPN、手动配置的 WireGuard)有几个痛点:

  1. 公网 IP / 端口暴露:必须有一台有公网 IP 的机器做接入点
  2. NAT 穿透困难:家用宽带、移动网络几乎都在 CGNAT 之后,没有公网 IP
  3. 证书 / PSK 管理:每加一台设备都要同步密钥
  4. 拓扑僵硬:星型拓扑(所有流量绕中心),不适合分布式团队
  5. 配置复杂:IPSec IKEv2 的配置语法复杂到"配置 1 天,能用 1 小时"

Tailscale 用三个手段解决这些问题:

  • DERP 中继:自研的中继协议(DERP,全称 Detoured Encrypted Routing Protocol),所有节点通过 HTTPS 与 DERP 服务器通信,作为 NAT 穿透失败时的兜底路径
  • 控制面与数据面分离:节点身份由控制面(OAuth 登录)管理,节点之间不信任 IP,而是信任"经过认证的设备 ID"
  • 节点间直连优先:能直连时建立 WireGuard 直连(依赖类 STUN 的探测,STUN 即 Session Traversal Utilities for NAT,让 NAT 后的设备获知自己的公网地址映射),不能直连时降级到 DERP 中继

架构:控制面 / 数据面分离

Tailscale 是典型的 “control plane + data plane” 分离架构:

                Control Plane (Tailscale coordination server)
                - 设备身份(OAuth → node key)
                - ACL 规则(基于 tag、user、group)
                - 网络拓扑(netmap)分发
                            ▲
                            │ TCP 443(Noise 协议封装)
                            │
        ┌───────────────────┴───────────────────┐
        │                                       │
    Node A                              Node B
    tailscaled daemon                   tailscaled daemon
    - WireGuard interface               - WireGuard interface
    - 与对端建立 WG 隧道                - 接收来自 A 的握手
    - 直连失败 → DERP 中继               - 直连失败 → DERP 中继
  • 控制面:每个节点与 coordination server 保持长连接,同步网络映射(netmap,即全网的节点列表、端点与密钥)、ACL 策略、节点密钥轮换等信息
  • 数据面:节点之间直接用 WireGuard 协议通信。注意端口与 WireGuard 原生实现的 51820 不同:tailscaled 默认监听 UDP 41641,端口被占用时会改用随机端口

这个分离让"策略"与"流量"解耦:修改 ACL 不需要重启连接,新节点加入立即生效。所有设备组成一个私有网络,Tailscale 称之为 tailnet。

WireGuard 是数据面

WireGuard 是 Jason Donenfeld 设计的现代 VPN 协议,加密套件固定:

  • Curve25519 密钥交换
  • ChaCha20-Poly1305 加密与认证(RFC 7539 AEAD 构造)
  • BLAKE2s 哈希与握手包消息认证
  • HKDF 密钥派生

WireGuard 的特点是:

  • 代码量刻意精简(Linux 内核实现在 drivers/net/wireguard 下共约 6000 行,含头文件),攻击面小,可人工审计
  • 加密套件固定,没有"算法协商"环节,避免配置错误
  • Linux 上运行在内核态,性能接近物理网络

Tailscale 直接复用 WireGuard 作为加密层,自己不做加密协议,只在其上做身份编排。注意:WireGuard 本身的密钥是静态的(每个节点一对长期密钥),Tailscale 的核心增量是把这些密钥的生成、分发、轮换交给控制面自动完成——这也是它区别于"手动配置 WireGuard"的根本所在。

NAT 穿透:STUN 式探测 + DERP 中继

Tailscale 的 NAT 穿透流程:

  1. 节点 A、B 上线后,向控制面注册自己的公网端点(IP:port,由类 STUN 的探测获得)
  2. A 想访问 B 的 Tailscale IP(100.64.0.0/10 网段内的地址)
  3. A 先尝试与 B 的公网端点建立 WireGuard 直连
  4. 直连成功 → 流量持续走直连(低延迟、不经过第三方)
  5. 直连失败(双方都在 NAT 后)→ 通过 DERP 服务器中继

DERP 不只是兜底:Tailscale 在全球运行 28 个区域的 DERP 中继集群(共 88 个节点,2026-09),客户端会自动选择延迟最低的节点。组织也可以自建 DERP 以满足合规与数据主权要求。

当双方都在 CGNAT 之后时,直连通常无法建立,DERP 中继就成为实际路径——所以中继的吞吐与两地距离直接决定这类场景下的体验。

快速起步

# 1. 安装
# macOS: brew install tailscale
# Linux: curl -fsSL https://tailscale.com/install.sh | sh
# Windows / iOS / Android:直接安装官方客户端

# 2. 登录(OAuth 身份认证)
sudo tailscale up
# 浏览器跳转到 Google / Microsoft / GitHub 登录
# 登录后自动获得 100.64.0.0/10 网段内的 Tailscale IP

# 3. 在另一台机器重复上述步骤
# 两台机器现在可以互访

跨平台覆盖:

  • Linux:优先用内核 WireGuard,也支持用户态实现(wireguard-go)
  • macOS / Windows:用户态 tun(utun / wintun)
  • iOS / Android:原生 SDK,系统层提供 VPN 配置
  • NAS / 路由器 / 云主机:Synology、OpenWrt、AWS、GCP、Azure 等都有官方或社区安装方式

ACL:身份驱动的策略

Tailscale 的 ACL(访问控制列表)是 HuJSON 格式——JSON 的超集,允许注释和尾随逗号:

{
  "acls": [
    // 开发组可以访问 web 节点的 80/443 端口
    {"action": "accept", "src": ["group:dev"], "dst": ["tag:web:80,443"]},
    // 所有成员可以经出口节点访问互联网
    {"action": "accept", "src": ["autogroup:members"], "dst": ["autogroup:internet:*"]}
  ],
  "groups": {
    "group:dev": ["[email protected]", "[email protected]"]
  },
  "tagOwners": {
    "tag:web": ["autogroup:admin"]
  }
}

策略关键概念:

  • users / groups:来自 OAuth 身份,不是用户自己声明
  • tags:节点标签(如 tag:prod-db),用于识别节点角色,并配合 tagOwners 限制谁能打标签
  • autogroup:预定义组。autogroup:members 是所有 tailnet 成员;autogroup:internet 只能用在目标(dst)位置,表示"经出口节点访问的互联网"

规则只有 accept 一种动作,未被放行的流量一律默认拒绝。策略由控制面推送到所有节点,客户端本地执行——不需要中心网关。新建 tailnet 时默认策略是成员间全互通,管理员可以在此基础上收紧。

MagicDNS:内置内网 DNS

装好 Tailscale 后,不仅能用 IP 访问对端,还能直接用 hostname:

ping my-macbook              # 设备 hostname 直接解析到 Tailscale IP
ssh pi4                      # 树莓派的主机名
curl http://nas:8080         # NAS 上的服务

MagicDNS 把"设备 hostname → Tailscale IP"的映射自动同步,不需要维护 /etc/hosts。它还支持 split DNS:让特定域名走指定 DNS 服务器(比如公司内网域名走内网 DNS)。

共享节点 / 出口节点 / 子网路由

Tailscale 默认只连自己的设备,组网需求往往不止于此。三个扩展能力:

  1. 共享节点:把节点 A 共享给用户 B,B 可以访问 A 上的服务,但看不到 A 的其它流量
  2. 出口节点(Exit Node):把节点 A 设为出口节点,其它节点通过 A 转发流量——相当于"借用 A 的网络出口",公共 Wi-Fi 场景很常用
  3. 子网路由(Subnet Router):节点 A 暴露它背后的局域网段(如 192.168.1.0/24),让其它 Tailscale 节点能访问 A 背后的 LAN,无需每台设备都装客户端

这也让 Tailscale 不只是"个人 VPN":把 AWS VPC 和办公网络通过一台子网路由器接通,就能实现跨云内网互通。

Tailscale SSH 与 Serve / Funnel

SSH 免公钥、HTTPS 免证书,这两件事 Tailscale 都做进了客户端。

Tailscale SSH:基于身份的 SSH,免去公钥分发与管理。

sudo tailscale up --ssh
ssh pi4   # 使用 tailnet 身份认证,无需配置 authorized_keys

谁能登录哪台机器,由策略文件里的 ssh 规则决定(与网络层 ACL 是分开的一节),支持 check 动作要求定期重新认证。登录与执行记录在控制台集中可查,服务器端不再维护 authorized_keys。

Tailscale Serve / Funnel:把本地服务暴露出去。

tailscale serve http://localhost:3000   # 在 tailnet 内提供 HTTPS 访问
tailscale funnel 8080                   # 暴露到公网(*.ts.net 域名)

证书由 Tailscale 自动申请并续期——按每台机器的域名(机器名.尾域名.ts.net)单独签发,不需要自己跑 certbot。两者在免费 Personal 计划下都能用;区别在于 Serve 只面向 tailnet 内部,Funnel 把服务发布到公网。

一次连接的完整路径

把上面的机制串起来:在 MacBook 上执行 ssh pi4,连一台在 NAT 后面的树莓派,会依次发生这些事。

  1. pi4 这个名字先交给 MagicDNS(100.100.100.100),返回它的 Tailscale IP。映射来自控制面下发的 netmap,本机不做任何 hosts 配置。
  2. tailscaled 在本地查 netmap,拿到 pi4 的节点公钥和已知端点(上一轮注册的公网 IP:port),同时在本地执行 ACL:规则不允许的话,到这里就结束了。
  3. 两端交换打洞探测包,尝试在各自 NAT 上开出直连通道。家用宽带大多能成功,得到一条点对点 WireGuard 隧道。
  4. 如果两端都在 CGNAT 后面打不通,流量自动改走延迟最近的 DERP 区域中继——用户无感知,只是延迟变高。用 tailscale ping pi4 可以看出当前是直连还是经 DERP 中继。
  5. sshd 收到连接。若开启 Tailscale SSH,身份直接取自 tailnet(用户名 + 设备),查 ssh 策略放行;否则按常规 authorized_keys 验证。

整条路径里没有一步需要登录路由器或开端口。控制面只在第 1、2 步提供元数据,实际流量始终走第 3 步的直连或第 4 步的中继。

与 ZeroTier、Cloudflare Tunnel 的取舍

维度TailscaleZeroTierCloudflare Tunnel
加密层WireGuard自研加密协议TLS / QUIC
控制面Tailscale 公司(可自建 Headscale)ZeroTier 公司(可自建 controller)Cloudflare
身份层OAuth邮箱 + 邀请Cloudflare Access
NAT 穿透DERP + STUN 式探测自研协议仅出站(无需穿透)
拓扑meshmesh / hub-spoke单向(公网到内网)
自托管能力Headscale(协议兼容)自建 controller不支持
免费额度设备不限 / 6 用户25 设备不限

决策建议:

  • 开发者 / SRE、个人 / 小团队 → Tailscale(上手最快)
  • 需要控制面自托管、数据主权 → Headscale
  • 只把内网服务暴露给公网,不做 mesh → Cloudflare Tunnel
  • 已有 ZeroTier 节点、需要协议兼容 → 保留 ZeroTier

自托管 Headscale

Tailscale 客户端代码大部分开源,但控制面闭源。控制面必须自托管(合规、数据主权)时,社区方案是 Headscale:

# 1. 准备目录,下载与你所用版本一致的示例配置
mkdir -p ./headscale/config ./headscale/lib && cd ./headscale
# 到 github.com/juanfont/headscale 找对应版本 tag,
# 下载仓库里的 config-example.yaml 存为 ./config/config.yaml 并按需修改

# 2. 启动(配置目录只读挂载,数据目录可写)
docker run \
  --name headscale \
  --detach \
  --volume "$(pwd)/config:/etc/headscale:ro" \
  --volume "$(pwd)/lib:/var/lib/headscale" \
  --publish 127.0.0.1:8080:8080 \
  docker.io/headscale/headscale:latest \
  serve

生产环境应把 latest 换成固定版本号,并保证配置文件与镜像版本一致。注意 Headscale 官方明确表示不支持也不鼓励容器方式部署,上面是官方文档给出的社区维护流程;更稳妥的做法是用二进制直接运行。

客户端指向自建控制面:

sudo tailscale up --login-server=https://headscale.example.com

Headscale 实现了 Tailscale 的控制面 API,但功能范围小于官方控制面,也没有官方 Web 控制台(靠 CLI 或第三方 UI 操作)。官方新功能上线后,Headscale 的跟进通常有滞后,大规模使用前先核对所需功能是否已支持。

常见坑

1. DERP 中继的吞吐与延迟

DERP 是所有 Tailscale 客户共享的中继基础设施,跨区域大流量会受限于中继节点吞吐与两地距离。对带宽敏感的业务,建议自建 DERP(区域 ID 900–999 保留给自建节点)或让两端尽量走直连。

2. ACL 的两个反直觉行为

Tailscale ACL 只有 accept 一种动作,没有 deny——所有未被规则放行的流量默认拒绝。由此带来两个容易踩的点:

  • 省略 acls 节等于全放行。策略文件里完全没有 acls 部分时,Tailscale 应用"默认互通"策略,所有成员可以互访;想拒绝全部流量,写一个空的 acls: [] 才行。新旧策略交接时容易在这里翻车。
  • 规则没写全比写错更危险。新增一台服务器后忘了给它加放行规则,它和其他节点就是完全不通的,现象上和故障一模一样。

写复杂策略时把预期写进 tests 字段,控制台推送前会自动验证:

"tests": [
  {
    "src":     "[email protected]",
    "accept":  ["tag:web:443"],
    "deny":    ["tag:db:5432"]
  }
]

3. MagicDNS 与内网 DNS 的冲突

MagicDNS 启用后,客户端会把 DNS 指向 100.100.100.100,由 Tailscale 接管解析。如果内网已有自己的 DNS,需要在管理控制台的 DNS 页面配置 split DNS(拆分解析):把特定域名(如 internal.corp)路由到内网 DNS 服务器(如 10.0.0.53),其余域名仍走系统默认。跳过这一步的典型症状是:Tailscale IP 能 ping 通,公司内部域名解析失败。

4. 客户端身份的吊销

节点被吊销后,已建立的 WireGuard 隧道不会立刻断开:各节点的过滤规则要等下一次 netmap 同步才生效(控制面通过长连接推送变更,通常几秒到几分钟内)。安全要求高的环境,应配合审计日志监控异常连接。

何时用 / 何时不用

适合:

  • 远程办公 / 分布式团队
  • 跨云 VPC 互通(AWS + GCP + Azure + 自建机房)
  • 调试时让"家里电脑 / 公司电脑 / 服务器"互通
  • IoT 设备远程接入(Raspberry Pi + Tailscale)
  • 给客户共享测试环境(共享节点)

不适合:

  • 大流量且两端难以直连的场景——流量会长期压在 DERP 中继上,带宽和延迟都不理想,应评估自建 WireGuard 或企业级方案
  • 需要客户端在用户设备上无感安装——Tailscale 需要显式安装
  • 已深度绑定 ZeroTier / WireGuard 自建的场景——迁移成本需要评估

阅读路径

  1. 官方文档 tailscale.com/kb——先看 “How Tailscale works”
  2. 源码 cmd/tailscaled/——理解 daemon 启动流程
  3. DERP 协议实现在仓库 derp/ 目录,WireGuard 是外部依赖
  4. Headscale 文档 headscale.net——如果要自托管控制面

参考资源

参与讨论

使用 GitHub 登录。欢迎补充事实、异议与实践。