Headscale
更新于 2026-10-29 16:03:14 · 创建于 2026-10-29 16:03:08
一句话定位
Headscale 是 Tailscale 控制服务器的开源自托管实现。客户端仍然是官方的 tailscale,WireGuard 数据面也完全没变——它只把「谁和谁组成一张网、每台机器分到哪个 100.x 地址、哪些路由被批准」这件事,从 Tailscale 的云端搬回你自己的服务器上。
45,157★、BSD-3-Clause、Go、当前 v0.29.6(2026-10-24),文档在 headscale.net。
先搞清楚它替换的是哪一半
Tailscale 由两层组成:
| 层 | 谁来做 | 开不开源 |
|---|---|---|
| 数据面:WireGuard 加密隧道、NAT 穿透、DERP 中继 | 官方 tailscaled 客户端 |
开源(BSD-3,即 tailscale/tailscale 这个仓库) |
| 控制面:公钥交换、地址分配、ACL、路由审批 | Tailscale 的协调服务器 | 闭源(SaaS) |
Headscale 只做第二行。所以:
- 流量不经过你的服务器(除非打洞失败走 DERP 中继),节点之间仍然是端到端 WireGuard;
- 你不需要给客户端打补丁,官方客户端加
--login-server就能连; - 你的服务器挂了,已建立连接的节点还能继续通信一段时间,只是新节点注册不上、netmap 更新停了。
控制面到底干了什么
- 交换 WireGuard 公钥,向每个节点下发 netmap(谁在线、各自地址、可用路由);
- 分配内网地址:默认
100.64.0.0/10(CGNAT 段)和fd7a:115c:a1e0::/48(Tailscale ULA); - 用户与节点隔离:多用户、多节点,预授权 key 绑定用户;
- ACL / policy:hujson 格式的声明式访问控制,可 GitOps;
- MagicDNS:给节点发短域名;
- DERP map 下发:告诉客户端有哪些中继可用;
- 路由审批:子网路由(subnet router)和出口节点(exit node)需要服务端批准才生效。
部署(v0.29.6 的正确姿势)
官方立场要先知道:README 明说「我们不支持也不鼓励用反向代理和容器来运行 Headscale」。这不是嘴硬——控制面涉及 Noise 握手、gRPC 与 TLS,反代配置错一层就会出各种诡异问题。所以首选原生二进制 + systemd + 一个真域名 + 真证书。
最小可用配置(节选自 config-example.yaml,v0.29.6 标签版):
server_url: https://hs.example.com:443 # 客户端能访问到的 https 地址
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090 # 别暴露到公网
grpc_listen_addr: 127.0.0.1:50443 # CLI 远程管理用,需有效证书
grpc_allow_insecure: false
trusted_proxies: [] # 只有前面真挂了反代才填
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes: # 必须是 Tailscale 标准段的子集
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
allocation: sequential # 或 random
derp:
server:
enabled: false # 自建 DERP 时才开,且 server_url 必须 https
urls:
- https://controlplane.tailscale.com/derpmap/default
database:
type: sqlite # 也支持 postgres
dns:
magic_dns: true
base_domain: example.internal
policy:
mode: file # 或 database,用 CLI 管
taildrop:
enabled: true
unix_socket: /var/run/headscale/headscale.sock
几个必踩点:
prefixes越界会「坏得很隐蔽」:配置注释原文说,客户端对这些网段有硬编码假设,用了 CGNAT/ULA 之外的范围会 break in subtle, hard-to-debug ways;server_url必须含 https 和端口,且换域名等于要所有客户端重新登录;trusted_proxies别乱填:留空时忽略X-Real-IP/X-Forwarded-For;你在没有反代的情况下填了,客户端就可以伪造来源 IP(和 RustDesk 那个安全公告同款问题);derp.server.enabled: true会内置 DERP + STUN(UDP 3478),好处是完全不依赖 Tailscale 的基础设施,代价是必须自己有 TLS;logtail.enabled默认 false,开了会让客户端把日志发给 Tailscale Inc.,自托管场景基本不会开。
客户端接入
# 服务端建用户、发预授权 key
headscale users create alice
headscale preauthkeys create --user alice --expiration 24h
# 每台机器上
tailscale up --login-server https://hs.example.com --authkey <key>
不预授权就走交互式:客户端给出 nodekey,服务端执行
headscale nodes register --user alice --key <nodekey>
子网路由 / 出口节点的完整流程(容易漏掉「审批」这一步):
# 网关机器上宣告网段
tailscale up --login-server https://hs.example.com --advertise-routes=192.168.1.0/24
# 服务端批准
headscale routes list
headscale routes enable -r 1
# 其它客户端接受
tailscale up --accept-routes
出口节点同理:宣告方 --advertise-exit-node,使用方 --exit-node=<100.x 地址>。
能做到什么、做不到什么
能做到:单 tailnet 自托管、多用户、预授权 key、hujson ACL、MagicDNS、子网路由、出口节点、Taildrop、内置 DERP、OIDC 登录(oidc 段,可接 Keycloak / Authentik,支持 allowed_domains / allowed_groups / PKCE)。
做不到(重要):
- 只有一张 tailnet,不支持多租户/多组织。官方定位写得很清楚:面向 self-hoster、爱好者、小型开源组织;
- 没有 Web 管理界面,只有 CLI + gRPC;
- 没有 Tailscale 的企业能力:SSO/SCIM 目录同步、设备姿态检查、Serve/Funnel 的公网入口、App Connectors 那一套;
- 客户端新特性可能滞后:某些 Tailscale 新功能依赖控制面支持,Headscale 需要跟进;跨版本混用要对照文档的支持表;
- 官方不为「反代 + 容器」部署背书。
升级比你想的危险
版本号还是 0.x,但配置文件键名和数据库结构改得不客气:policy 从纯文件走向 file/database 双模式、grpc_listen_addr / grpc_allow_insecure / trusted_proxies 这类键是后加的、prefixes 从单值变 v4/v6 两段式。所以:
- README 的要求:用哪个 tag,就看哪个版本的文档(
headscale.net/stable/对应稳定版,/development/对应 main); - 升级前读 release notes 里的数据库迁移说明,先备份;
- 备份清单:sqlite 文件 +
noise_private.key+derp_server_private.key。少一个,重建后所有节点都得重新注册。
其它坑:
- 时钟必须准:TLS 与 Noise 握手都对时间敏感,容器/虚拟机休眠后漂移会表现为「莫名其妙连不上」;
- 公网 DERP 仍走 Tailscale 基础设施:默认
derp.urls指向官方 derpmap,中继流量经过他们。要彻底自主就自建 DERP; - Taildrop 是全网络开关(
taildrop.enabled),没有按用户粒度; - 节点过期时间由
node.expiry控制,用 OIDC 时还可能被use_expiry_from_token覆盖。
和 Tailscale 的关系(不是敌对)
- 数据面 100% 共用,所以 Headscale 的体验上限由官方客户端决定;
- 差别只在控制面:Tailscale 是托管 SaaS(有免费额度,商业功能收费);Headscale 自托管,功能窄、没界面、责任自负;
- 官方并不打压:README 明确写着有活跃维护者在 Tailscale 任职,并获准在工作时间投入这个项目,其提交由其他维护者 review;FOSDEM 2026 上还有一场演讲叫《Headscale & Tailscale: The complementary open source clone》。
选择逻辑很朴素:
| 你的情况 | 选 |
|---|---|
| 想零运维、要 SSO/审计/商业支持 | Tailscale |
| 数据主权、公司内网、不能依赖外部 SaaS | Headscale |
| 只是几台机器互通、要图形界面 | ZeroTier(id=55) |
| 完全没有公网服务器,要纯去中心化 | EasyTier(id=53) |
二开 / 二次利用
- 自动化开通:
proto/下的 gRPC 定义 + CLI 都是薄封装,写个脚本批量建用户、发 key、开路由很轻松; - GitOps:
policy.hujson是纯声明式文件,policy 走mode: file就能纳入版本管理,改完重启生效; - 改行为:核心在
hscontrol/(state、db、dns、derp、routes、policy),想加自定义字段或审批流从这儿下手; - 接自家身份:
oidc段配 Keycloak/Authentik,allowed_groups做准入,比手工建用户省事; - 多环境的低成本方案:一台便宜 VPS + sqlite + 官方 DERP,一个人管几十台设备毫无压力。
一句话总结
Headscale 用 45k 星的体量证明了一件事:Tailscale 真正难的部分是客户端和穿透,控制面其实可以不依赖他们。它把「设备地址簿 + 公钥交换 + 路由审批」这套逻辑重写成 Go 服务,让你用一台 VPS 换来自托管、无账号、无额度限制的 tailnet。代价是界面没有、企业功能没有、升级要看迁移说明、部署别玩容器反代——换来的是你完全掌握自己的网络账本。