自建 Headscale 服务器部署 Wiki
自建 Headscale 服务器部署 Wiki
基于 Headscale 0.28.0 + Caddy + Tailscale,使用自定义域名搭建私有 Tailscale 控制服务器。
一、架构设计
客户端 (Tailscale)
│
│ HTTPS (443)
▼
Caddy 反向代理
example.com / www.example.com
自动申请 TLS 证书 (Let's Encrypt)
│
│ HTTP (8081, 本地)
▼
Headscale 控制服务器
监听 0.0.0.0:8081
SQLite 数据库
│
│ DERP 中继(使用 Tailscale 官方节点)
▼
各节点之间 P2P 或中继通信
组件职责:
| 组件 | 职责 |
|---|---|
| Caddy | 反向代理 + 自动 HTTPS 证书 |
| Headscale | 开源 Tailscale 控制服务器,管理节点注册、密钥、ACL |
| Tailscale 客户端 | 各设备上的 headscale客户端,连接到自建控制服务器 |
| DERP | 中继服务器,P2P 打洞失败时使用(此处复用 Tailscale 官方节点) |
二、前置条件
- Ubuntu 22.04 / 24.04 服务器,有公网 IP
- 域名已将 A 记录指向服务器公网 IP(本例:
example.com和www.example.com) - 服务器开放端口:
80(HTTP 验证)、443(HTTPS)
三、安装 Caddy
# 安装 Caddy(官方源)
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy
配置 Caddyfile
sudo vim /etc/caddy/Caddyfile
写入以下内容:
example.com, www.example.com {
reverse_proxy localhost:8081 {
header_up Host {http.request.host}
header_up X-Forwarded-Host {http.request.host}
header_up X-Forwarded-Proto {http.request.proto}
header_up X-Forwarded-For {http.request.remote.host}
}
encode gzip zstd
header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
}
}
# 格式化并验证配置
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
# 重载 Caddy
sudo systemctl reload caddy
四、安装 Headscale
国内访问 GitHub 可能受限,使用镜像站下载。
# 下载 0.28.0 deb 包(使用 kkgithub 镜像)
wget -O headscale_0.28.0.deb \
"https://kkgithub.com/juanfont/headscale/releases/download/v0.28.0/headscale_0.28.0_linux_amd64.deb"
# 安装
sudo apt install -f ./headscale_0.28.0.deb
# 启动并设置开机自启
sudo systemctl enable --now headscale
五、配置 Headscale
sudo vim /etc/headscale/config.yaml
完整配置如下:
---
server_url: https://www.example.com
listen_addr: 0.0.0.0:8081
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
policy:
mode: disabled
dns:
magic_dns: true
base_domain: headscale.internal
override_local_dns: true
nameservers:
global:
- 223.5.5.5
- 223.6.6.6
derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: true
log:
level: info
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
# 重启服务
sudo systemctl restart headscale
sudo systemctl status headscale
六、创建用户并添加节点
创建用户
sudo headscale users create myfamily
# 查看用户列表(含 ID)
sudo headscale users list
生成 Pre-Auth Key(推荐方式)
# 生成可复用的 authkey,有效期 24 小时
sudo headscale preauthkeys create --user myfamily --reusable --expiration 24h
输出示例:
hskey-auth-xNBe_HAAxdKh-rH4mMfD58A7CXZbrExrxzUKAvlc-fJioNS25S9caoKp5bqZMNlhAgBL1l-TREBdn
客户端接入
Windows / macOS / Linux:
tailscale up --login-server=https://www.example.com --authkey=<上面生成的key>
Android / iOS: 参考 官方文档,在客户端设置中填写自定义控制服务器地址后使用 authkey 登录。
查看已注册节点
sudo headscale nodes list
七、常见坑及处理措施
坑 1:ip_prefixes 字段不被识别
报错: no IPv4 or IPv6 prefix configured, minimum one prefix is required
原因: Headscale 0.23+ 将字段从 ip_prefixes 改为 prefixes,格式也发生变化。
处理: 使用新格式:
# ❌ 旧版写法
ip_prefixes:
- 100.64.0.0/10
# ✅ 新版写法
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
坑 2:server_url 与 base_domain 冲突
报错: server_url cannot be part of base_domain in a way that could make the DERP and headscale server unreachable
原因: Headscale 会检测 server_url 的域名是否属于 base_domain 的子域(或同域)。如果是,Magic DNS 会劫持控制服务器域名,导致客户端断连。
例如 server_url 为 www.example.com,base_domain 为 example.com 或 ts.example.com 都会触发此问题(父子域关系)。
处理: base_domain 使用与 server_url 完全无关的域名:
dns:
base_domain: headscale.internal # ✅ 完全隔离,不需要真实注册
坑 3:数据库字段改名
报错: invalid database type "", must be sqlite, sqlite3 or postgres
原因: 新版将顶层 db_type / db_path 改为嵌套结构。
处理:
# ❌ 旧版写法
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
# ✅ 新版写法
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
坑 4:旧数据库 Schema 不兼容
报错: SQLite schema failed to validate: Remove table "machines" ...
原因: 旧版本遗留的数据库表结构与新版不兼容,无法自动迁移。
处理: 若无重要数据,删除数据库文件让 Headscale 重建:
sudo systemctl stop headscale
sudo rm /var/lib/headscale/db.sqlite
sudo systemctl start headscale
⚠️ 若有已注册节点需保留,应先降级到原版本导出数据,或查阅对应版本的迁移文档。
坑 5:--user 参数接受 ID 而非用户名
报错: invalid argument "myfamily" for "-u, --user" flag: strconv.ParseUint: parsing "myfamily": invalid syntax
原因: 部分版本的 preauthkeys create 命令 --user 参数只接受数字 ID。
处理:
# 先查询用户 ID
sudo headscale users list
# 使用 ID
sudo headscale preauthkeys create --user 1 --reusable --expiration 24h
坑 6:将节点 key 当 authkey 使用
报错: auth-key not found
原因: tailscale up 交互式登录产生的 nodekey:xxx 是节点密钥,需要在服务端用 headscale nodes register 来注册;而 --authkey 参数需要的是通过 headscale preauthkeys create 生成的 hskey-auth-xxx。
处理: 两种接入方式二选一:
# 方式一:服务端生成 authkey,客户端直接使用(推荐)
sudo headscale preauthkeys create --user myfamily --reusable --expiration 24h
tailscale up --login-server=https://www.example.com --authkey=hskey-auth-xxx
# 方式二:客户端生成 nodekey,服务端手动注册
tailscale up --login-server=https://www.example.com # 复制输出的 nodekey
sudo headscale nodes register --key nodekey:xxx --user myfamily
八、日常运维命令
# 查看服务状态
sudo systemctl status headscale
# 查看实时日志
sudo journalctl -u headscale.service -f
# 用户管理
sudo headscale users list
sudo headscale users create <name>
# 节点管理
sudo headscale nodes list
sudo headscale nodes delete --identifier <id>
# Pre-Auth Key 管理
sudo headscale preauthkeys list --user myfamily
sudo headscale preauthkeys expire --user myfamily --key <key>
# Caddy 配置重载
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo systemctl reload caddy
九、参考资料
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)