Tailscale 组网原理与自建简明指南
这篇文章用三句话讲清 Tailscale 的分层原理,再给出自建控制面(headscale)的简明配置步骤, 以及我在实践里踩过的坑。文中所有域名、IP、端口均为占位示例,照抄时请替换成你自己的。
一、原理:三句话模型
第一句:Tailscale 分成"控制面"和"数据面"两个完全独立的部分。 控制面(headscale 或官方服务)只负责认证、下发节点清单和密钥,它永远不转发你的数据; 数据在设备之间端到端加密直连。
第二句:直连需要"打洞"成功,打洞依赖两端的 NAT 类型。 家用路由器多为锥形 NAT(好打),手机蜂窝网多为运营商对称 NAT(极难打),公司网络常常也受限。
第三句:打洞失败时,流量自动降级走 DERP 中继。 DERP 是双方都够得着的公网固定点,只搬运密文、看不到内容,代价是延迟更高。
理想情况(打洞成功): A ──── WireGuard 直连(端到端加密)──── B 受限情况(打洞失败): A ──> DERP 中继(公网可达点)──> B headscale 控制面:只负责"介绍"双方认识,不在数据路径上。
一个贴切的类比:headscale 是电话本(告诉你对方地址),DERP 是公共邮局(双方够不着时转交), 直连是两家之间的私人管道。电话本不递东西;邮局只在打不通时帮忙;私人管道通了就不用邮局。
常见误区
- "我自建了服务器,流量为什么不经过我的服务器?" —— 因为控制面本来就不该也不能转发: 设备间流量是端到端加密的,服务器没有会话密钥,拿到也是密文。
- "打洞失败是不是服务器配置问题?" —— 不是。打洞只取决于两端 NAT 的"可达性", 和服务器位置无关;但服务器/DERP 的地理位置决定中继时的延迟。
- "DERP 安全吗?" —— 中继只转发密文,自建与借用公共 DERP 在安全性上没有差别,差别只在延迟。
二、自建 headscale 简明步骤
1. 准备一台公网服务器
建议有固定公网 IP、位于你和多数设备之间网络质量较好的机房。域名解析一条 A 记录指向它,
例如 ts.example.com。
2. 安装并初始化 headscale(服务端)
# 以官方文档为准安装 headscale 后:
sudo headscale serve
# 创建你的第一个用户(小写)
sudo headscale users create alice
编辑配置文件(/etc/headscale/config.yaml),最关键的几项:
server_url: https://ts.example.com:8443 # 客户端接入地址,必须 https
prefixes:
v4: 100.64.0.0/10 # 默认网段;注意与自家内网/云厂商内网不要冲突
dns:
magic_dns: false
nameservers:
global:
- 1.1.1.1
⚠️ 经验教训:CGNAT 段(100.64.0.0/10)与部分云厂商的内网 DNS/镜像服务网段重叠。 一旦 tailscale 接管路由,云主机的 DNS 应答会被自己的防伪冒规则丢弃,表现为"断网但 resolv.conf 没问题"。 解法:客户端关闭 DNS 接管(--accept-dns=false);必要时关闭 netfilter 管理 (tailscale set --netfilter-mode=off,仅限纯节点、非子网路由/出口场景)。
3. 用 Nginx 做 TLS 反代(推荐)
headscale 本身可裸跑 HTTP,但客户端要求 https。用 Nginx + 免费证书最省事:
# /etc/nginx/sites-available/ts.example.com(要点:WebSocket/长连接代理)
server {
listen 8443 ssl;
server_name ts.example.com;
ssl_certificate /etc/ssl/ts.example.com.fullchain.crt;
ssl_certificate_key /etc/ssl/ts.example.com.key;
location / {
proxy_pass http://127.0.0.1:8080; # headscale 默认监听
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade; # 控制协议依赖升级
proxy_set_header Connection "upgrade";
proxy_buffering off;
}
}
4. 客户端入网
# 服务端生成一次性预授权密钥(24 小时有效示例)
sudo headscale preauthkeys create --user alice -e 24h
# 每台设备执行(Linux/macOS;Windows 用 tailscale.exe up)
sudo tailscale up --login-server https://ts.example.com:8443 --authkey hskey-auth-xxxx
5. 验证
tailscale status # 看到所有节点和在线状态
tailscale ping 100.64.0.2 # direct = 直连;via DERP(xx) = 走中继
tailscale netcheck # 看各 DERP 区域延迟与 UDP 连通性
三、可选:自建 DERP(让中继也快)
当设备间打洞失败(比如手机蜂窝网 ↔ 公司网络),流量会走 DERP。默认借用公共 DERP 地图, 国内设备往往被导向境外节点(如香港),延迟能到 400ms 量级。解法是在自己的公网服务器上开一个内嵌 DERP:
# headscale 配置里启用内嵌 DERP(v0.29+ 写法示意)
derp:
server:
enabled: true
region_id: 999
region_code: "cn-self"
region_name: "Self-hosted CN"
stun_listen_addr: "0.0.0.0:3478"
automatically_add_embedded_derp_region: true
ipv4: 1.2.3.4 # 你的公网 IP
urls:
- https://controlplane.tailscale.com/derpmap/default # 保留官方地图作冗余
- 需要放行 UDP 3478(STUN)与 DERP 的 HTTPS 端口(复用上一步的反代 +
/derp路径代理); - 客户端会自动测速并就近选择区域,无需手动配置;
- 实测效果示例:某对设备经境外中继约 400ms,切到自建国内中继后降到约 90ms。
四、排障速查
- 节点一直 offline —— 控制面可达性;密钥是否过期;客户端系统省电策略杀后台
- 延迟高但两端网络都"正常" —— 大概率在走境外 DERP——看 ping 输出里的
via DERP(xx) - 连不上但 resolv.conf 正常 —— 检查云厂商内网是否与 CGNAT 段重叠(见上文教训)
- exit node 很慢 —— 打洞失败走中继 + 出口机器本身的上行/无线状况
写完这篇,最深的感受是:Tailscale 架构的优雅在于"控制面不管数据",代价是使用者必须理解 NAT 与中继的边界。理解了这三句话,绝大多数"为什么慢/为什么不通"都能自己定位了。
—— M-D,2026-09-09。示例地址均为占位,请勿对号入座。