起因
Tailscale 是 WireGuard-based 的 mesh VPN,体验绝佳:所有设备通过
控制平面"发现"互通,零端口转发。但:
- 控制平面是 Tailscale 公司的(数据不出公司是大忌行业)
- 免费层 100 设备限制
- 隐私敏感场景不想依赖商业服务
headscale 是开源的 Tailscale control plane 实现,自己跑一台
机器就能成为"自己的 Tailscale 公司"。客户端继续用 Tailscale 官方
app(功能完整)+ 连你的 headscale server。
架构
┌──────────────┐
│ headscale │ ← 自己跑,public 可达
│ (control) │
└──┬──────┬────┘
│ │
┌───────┘ └────────┐
│ │
[laptop] ←── mesh ──→ [server]
│ WireGuard │
└─── 互联 ──────────────┘
控制平面只协调 peer discovery + key exchange,不路由数据流量。
节点间 P2P 直连(NAT 穿透)或者 P2P 失败时 fallback 到 DERP relay。
装 headscale
需要一台公网可达的服务器(VPS)+ HTTPS(必须)。
# 二进制安装
HEADSCALE_VERSION=0.23.0
curl -fsSL https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_amd64.deb \
-o headscale.deb
sudo dpkg -i headscale.deb
或 Docker:
# docker-compose.yml
services:
headscale:
image: headscale/headscale:0.23.0
command: serve
restart: unless-stopped
ports: ["8080:8080", "9090:9090"]
volumes:
- ./config:/etc/headscale
- ./data:/var/lib/headscale
配置
/etc/headscale/config.yaml(关键字段):
server_url: https://hs.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
ip_prefixes:
- 100.64.0.0/10 # tailscale 默认 CGNAT 段
- fd7a:115c:a1e0::/48
derp:
server:
enabled: false # 自己跑 DERP 可选;先用官方 DERP
urls:
- https://controlplane.tailscale.com/derpmap/default
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
log:
level: info
oidc:
# 可选:用 GitHub / Google / Authelia 等 SSO 登录
# issuer: https://auth.example.com
# client_id: ...
用 systemd
sudo systemctl enable --now headscale
sudo systemctl status headscale
需要 HTTPS 反代(nginx / Caddy)。hs.example.com 指向这台机器
+ TLS 证书。
创建 user + 设备 enroll
# 创建 user (一个 user 一组设备)
sudo headscale users create alice
# 客户端那边(macOS / Linux / iOS / Android / Windows)装 Tailscale,
# 但通过 --login-server 指向你的 headscale
sudo tailscale up --login-server https://hs.example.com
# 输出一个授权 URL,但 headscale 不能 auto-auth,要手动 register key:
# 看到 URL:
# To authenticate, visit: https://hs.example.com/register/abc123...
# 复制 nodekey 到 server 上:
sudo headscale nodes register --user alice --key nodekey:abc123...
或者用 pre-auth key(推荐脚本化):
sudo headscale preauthkeys create --user alice --reusable --expiration 24h
# 输出:xxx-yyy-zzz
# 客户端
sudo tailscale up --login-server https://hs.example.com --auth-key xxx-yyy-zzz
# 自动 enroll,无需手动 register
成功后:
sudo headscale nodes list
# ID | Name | User | IP | Online
# 1 | laptop | alice | 100.64.0.1 | yes
# 2 | server | alice | 100.64.0.2 | yes
节点间访问
ssh [email protected] # 通过 mesh VPN 访问
ping 100.64.0.2
或用 MagicDNS:
ssh user@server # tailnet 内 hostname 自动解析
要开 MagicDNS:
# config.yaml
dns:
magic_dns: true
base_domain: tailnet.example.com
override_local_dns: true
nameservers:
global:
- 1.1.1.1
每节点 tailscale.tailnet.example.com 自动可解析。
ACL(谁能访问谁)
// /etc/headscale/acl.hujson
{
"acls": [
// alice 的设备能互访
{"action": "accept", "src": ["alice"], "dst": ["alice:*"]},
// bob 只能访问 server
{"action": "accept", "src": ["bob"], "dst": ["alice:server:22"]},
// 默认 deny(不写 accept 的都不通)
],
"groups": {
"group:admins": ["alice"],
},
"tagOwners": {
"tag:prod-server": ["group:admins"],
},
}
sudo headscale policy set -f /etc/headscale/acl.hujson
类似 K8s NetworkPolicy 但更简单。
subnet routes(让 VPN 节点暴露内网)
server 节点 advertise 内网:
sudo tailscale up --login-server https://hs.example.com \
--advertise-routes=192.168.1.0/24
headscale 上 approve:
sudo headscale nodes routes list
sudo headscale nodes routes enable -r 1
之后所有 mesh 节点能通过这个 server 访问 192.168.1.x(家庭内网)。
等于"VPN 入口"。
exit nodes(用某节点作出口)
# server 节点 advertise 为 exit node
sudo tailscale up --advertise-exit-node
# headscale approve
sudo headscale nodes routes enable -r 1 --all
# 客户端用:
sudo tailscale up --exit-node=server
客户端流量全部走 server 出公网。"自建 VPN" 替代商业 VPN。
跟 cloud Tailscale 对比
| Tailscale Cloud | headscale | |
|---|---|---|
| 控制平面 | Tailscale 公司 | 自己 |
| 数据流量 | 不经控制平面 | 不经控制平面 |
| 客户端 app | 一样 | 一样(开源 tailscaled) |
| ACL UI | Web 仪表盘 | CLI / hujson 文件 |
| OIDC | 完善 | 基础支持 |
| MagicDNS | ✅ | ✅ |
| DERP relay | 全球 + 免费 | 用官方 DERP 或自建 |
| 价格 | 免费 100 节点 / 团队收费 | 完全免费 |
| 适合 | 普通团队 | 大规模 / 隐私敏感 |
非企业 + 100 节点以内 → 用 cloud Tailscale 省心。
100 设备 / 隐私敏感 / 跑公司基础设施 → headscale 自托管。
与 WireGuard 直接配相比
裸 WireGuard:
- 每加设备改所有节点 conf
- 没 NAT 穿透(双 NAT 后设备难互联)
- 没 MagicDNS
- 维护 100 节点想哭
Tailscale / headscale:
- 自动 P2P discovery + NAT 穿透
- 加设备一行命令
- ACL 中央管理
- MagicDNS
mesh 规模上去后 headscale > 裸 WireGuard 远不止一个量级。
实际效果
我家庭 + 公司 + VPS 一共 12 个设备:
- 手机 / 笔记本 在外能直连家里 NAS(之前要开 OpenVPN 客户端)
- 公司 / 家里互通(VPC peering 替代品)
- 一台 VPS 当 exit node:手机走 VPN 翻墙
- ACL 让"工作笔记本只能访问 work server" 严格隔离
- headscale 自己跑在一台 $5 / 月 VPS 上,零成本控制平面
完全替代了我之前的 OpenVPN + 维护 WireGuard config。
踩过的坑
-
server_url 错 → 客户端连不上。必须包含 https:// 和正确域名,
且证书有效。 -
客户端不接受
--login-server指向 IP:必须用域名 + 证书。 -
NAT 双层穿不过 → fallback 到 DERP relay。自建 DERP server 加速。
-
OIDC 配 SSO 时 callback URL 错:headscale callback 是
/oidc/callback,注册 SSO 时填对。 -
0.22 → 0.23 数据库迁移:headscale 大版本升级偶尔需 migrate
命令。release notes 仔细看。
登录后参与评论。