Headscale 用户使用手册
以官方文档内容为主,
> 补充为实践说明。
官方文档:https://headscale.net/stable/
1. Configuration(配置)
- Headscale 从 YAML 文件加载配置。
- 默认搜索路径:
/etc/headscale$HOME/.headscale- 当前工作目录
- 用以下方式指定其他路径:
- 命令行参数
-c/--config - 环境变量
HEADSCALE_CONFIG
- 命令行参数
- 用
headscale configtest校验配置文件。 - 始终选择与所用发布版本相同的 GitHub tag,
main分支可能包含未发布的改动。
补充:
server_url是配置里最关键的项之一,必须和客户端实际访问的地址完全一致(协议、域名、端口)。写错的话,登录回调、OIDC 重定向、gRPC 远程连接都会出问题。- 配置文件里的相对路径是相对于配置文件所在目录,不是当前工作目录。证书路径、数据库路径、policy 路径都容易踩这个坑。
- 大部分配置改动需要重启才生效,但 policy 文件支持热重载,改策略不用重启。
- 参考样例一定用你当前版本 tag 下的
config-example.yaml,别用main分支的,格式可能已经变了。- 生产环境建议把配置放
/etc/headscale/,权限收紧(比如600),因为里面可能有 OIDC client secret、数据库密码等敏感信息。- 常见配置段:
server_url、listen_addr、metrics_listen_addr、grpc_listen_addr、database、dns、derp、oidc、policy、log。
2. Registration(节点注册)
身份模型
- 个人节点:由人类用户拥有,通常指终端设备(笔记本、工作站、手机),由单个用户管理。
- 标签节点:为网络提供服务(Web、数据库服务器),通常由团队管理。有额外限制,例如标签节点不允许 Tailscale SSH 登录个人节点。
- Headscale 实现 Tailscale 的身份模型:个人节点归 Headscale 用户所有,标签节点归 tag 所有。标签设备归到特殊用户
tagged-devices下。
补充:
- 这个身份模型是理解 Headscale 权限体系的基础。个人节点属于「人」,标签节点属于「服务」。
- 标签节点不能 SSH 进个人节点,是故意的安全设计,不是 bug。目的是防止被攻陷的服务节点横向移动到个人设备。
tagged-devices是内部特殊用户,你在headscale users list里可能看不到它,但标签节点都挂在它下面。
注册方式
两种主要方式:Web 认证 和 预认证密钥,都可用于注册个人和标签节点。
Web 认证(默认,交互式)
- 创建用户:
headscale users create <USER> - 客户端登录:
tailscale up --login-server <YOUR_HEADSCALE_URL> - 浏览器打开页面,拿到 Auth ID,批准节点:
headscale auth register --user <USER> --auth-id <AUTH_ID>
标签节点需要用户被授权,授权在 policy 的 tagOwners 段配置。客户端加 --advertise-tags tag:<TAG>,批准后节点归 tagged-devices 所有。
预认证密钥(非交互,适合自动化)
- 创建用户:
headscale users create <USER> - 查看 USER_ID:
headscale user list - 创建密钥:
headscale preauthkeys create --user <USER_ID> - 注册节点:
tailscale up --login-server <YOUR_HEADSCALE_URL> --authkey <YOUR_AUTH_KEY>
标签节点用 headscale preauthkeys create --tags tag:<TAG>,客户端不用再传 --advertise-tags,tag 会自动从密钥读取。
补充:
- Web 认证适合人工操作的终端设备;预认证密钥适合脚本、CI/CD、无人值守设备、批量部署。
- 预认证密钥默认一次性、1 小时有效。要复用加
--reusable,要改有效期加--expiration。- 忘了批准,节点会一直处于 pending 状态,
headscale nodes list能看到。- Headscale 数据库丢失 = 所有节点要重新认证,所以务必备份数据库。
- 客户端注册后会保存状态;如果只是重启 Headscale,节点一般不用重新认证。
- 标签节点注册时,Headscale 会检查
<USER>是否有权注册该 tag,检查通过后节点归tagged-devices。
3. OpenID Connect(OIDC)
Headscale 支持通过外部身份提供商进行 OIDC 认证。
配置
- Headscale 侧:配置文件的
oidc段包含所有可用选项、描述和默认值。 - IdP 侧:参考你的身份提供商官方文档,下方也有各 IdP 的具体配置提示。
基本配置通常需要:
- Issuer URL(Headscale 用 OpenID Connect Discovery 1.0 自动获取配置)
- Client ID
- Client Secret
- Redirect URI(如
https://headscale.example.com/oidc/callback)
启用 PKCE(推荐):为 OAuth 2.0 授权码流程增加一层安全,防止授权码拦截攻击。Headscale 和 IdP 都要配。
用户过滤:可按域名、邮箱地址、群组成员资格过滤,多个过滤器需全部通过。默认禁用,认证成功即允许加入。
- 按域名:只允许
example.com域名的邮箱 - 按邮箱:只允许
allowed_users列表里的邮箱 - 按群组:只允许特定群组成员
要求已验证邮箱,除非禁用邮箱验证。
控制邮箱验证:Headscale 使用 email_verified: true claim。IdP 不发送该 claim 或不需要验证时,可允许未验证邮箱。
自定义节点过期:通过顶层 node.expiry 配置。可手动让节点立即过期:
headscale node expire -i <NODE_ID>
在 policy 里引用用户:可用邮箱、用户名、提供商标识。用户标识必须包含单个 @。Headscale 用户名若不含 @,需在末尾追加,如 ssmith 写成 ssmith@。确保用户名本身不以 @ 结尾。
注意:很多 IdP 允许用户改自己资料,用户名或邮箱可能变,可能导致 policy 失效,或用户通过抢占已有用户名/邮箱获得更多权限。
提供商标识(providerId)唯一标识 OIDC 用户,行为良好的 IdP 保证它永不变。它是通常不透明的长字符串,目前只能从 API、数据库或 IdP 获取。可用 /api/v1/user 端点获取,在 policy 里引用时记得追加 @。
支持的 OIDC claims
| Headscale 字段 | OIDC claim |
|---|---|
| 邮箱 | email(仅同步已验证邮箱,除非禁用验证) |
| 显示名 | name |
| 用户名 | preferred_username |
| 头像 | picture |
| 提供商标识 | iss, sub |
| 群组 | 仅用于过滤 |
限制
- 只提供有限的 IdP 特殊行为支持。
- OIDC groups 不能用于 policy 规则。
- 用户名需符合:至少两个字符、只含字母数字连字符点下划线和最多一个
@、以字母开头。
已知兼容的 IdP
Authelia、Authentik、Google OAuth、Kanidm、Keycloak、Microsoft Entra ID。
- Authelia:完全支持。
- Authentik:完全支持。Headscale 不支持 JSON Web Encryption,
Encryption Key留空。 - Google OAuth:不发送
preferred_username,Headscale 里用户名会是空的。只需认证自己域名的用户可跳过验证流程。 - Kanidm:完全支持。允许组过滤需用完整 SPN。默认发完整 SPN 作为
preferred_username,可配成短用户名。 - Keycloak:完全支持。用组过滤需额外建
groupsclient scope 和 mapper。 - Microsoft Entra ID:需注册 App,配正确 scope 和 redirect URI。用组过滤时不要
groupsclaim,组要用组 ID(UUID)。
切换 OIDC 提供商
Headscale 只支持单个 OIDC 提供商,但存储每个用户的 provider identifier。切换时所有用户详情可能相同但标识不同,会导致无法创建新用户。需手动更新 users 表的 provider_identifier 列,值由 ID token 的 iss 和 sub 组成。
补充:
- OIDC 的核心价值是让用户自助注册,免去管理员手动
users create+ 批准,适合多用户环境。- 启用后,用户首次登录会自动在 Headscale 里创建。
- 用户名冲突是常见问题,尤其 Google 不返回
preferred_username时。- 换 IdP 很痛,因为
provider_identifier变了,得手动改数据库,这是已知痛点。- 建议生产开 PKCE,并配
allowed_domains/allowed_users/allowed_groups做访问控制。- OIDC 的 groups 只能用于过滤,不能写进 policy 规则,官方明确限制。
4. Routes(路由)
Headscale 支持路由通告,可管理子网路由器和出口节点。
- 子网路由器:把现有网络(VPC、本地网络)接入 tailnet,用于访问装不了 Tailscale 的设备,或逐步 rollout。
- 出口节点:把另一个 Tailscale 节点的全部互联网流量路由出去,用于不可信 Wi-Fi 或需要固定出口 IP 的场景。
子网路由器
需要双端同意:节点端 + 控制服务器端。可选 autoApprovers 自动批准。
配置节点:
sudo tailscale up --login-server <URL> --advertise-routes=10.0.0.0/8,192.168.0.0/24
已注册节点用:
sudo tailscale set --advertise-routes=10.0.0.0/8,192.168.0.0/24
最后开启 IP 转发。
控制服务器批准:
headscale nodes list-routes
headscale routes enable -r <ROUTE_ID>
使用方:
sudo tailscale set --accept-routes
用 policy 限制:默认无策略时所有节点可用这些路由,配 policy 可明确管理。示例策略定义三台主机,允许普通节点通过子网路由器访问内部服务的 80/443 端口,拒绝访问路由器本身。
自动批准:policy 的 autoApprovers 段可自动批准带特定 tag 的路由器宣告的路由。
出口节点
同样双端同意,可选自动批准。
配置节点:
sudo tailscale up --login-server <URL> --advertise-exit-node
已注册节点:
sudo tailscale set --advertise-exit-node
最后开启 IP 转发。
控制服务器批准:
headscale nodes list-routes
出口节点特征:宣告 0.0.0.0/0 和 ::/0。批准 IPv4 或 IPv6 任一即可,另一个自动批准。
使用方:
sudo tailscale set --exit-node myexit
用 policy 限制:用 autogroup:internet 控制谁能用出口节点,也可按用户/组分配特定出口节点。示例:alice 只能用 tag:exit1 的出口节点,bob 只能用 tag:exit2。
自动批准:autoApprovers 的 exitNode 段可自动批准带特定 tag 的出口节点。
高可用
多个子网路由器或出口节点可提供高可用。至少两个节点宣告相同前缀时默认启用。详见配置项 node.routes.ha。
故障排查
子网路由器或出口节点需要 IP 转发,参考官方 Tailscale 文档。
补充:
- 出口节点本质就是宣告
0.0.0.0/0和::/0。- IP 转发没开是这类问题最高频的故障原因。Linux 上一般是
net.ipv4.ip_forward=1和net.ipv6.conf.all.forwarding=1。- 双端同意(double opt-in)是安全设计:节点宣告 + 服务器批准,避免节点擅自转发流量。
- 多个节点宣告相同前缀时,客户端会自动选一个,这就是高可用的实现。
- 策略里
autogroup:internet是控制出口节点使用的关键。- 官方 Tailscale 文档有各系统开启 IP 转发的方法,可直接参考。
5. TLS
Headscale 可通过 TLS 暴露 Web 服务。
自带证书
设置 tls_cert_path 和 tls_key_path。相对路径相对于配置文件所在目录。证书应包含完整链,否则部分客户端(如 Android)会拒绝。
Let’s Encrypt / ACME
设置 tls_letsencrypt_hostname,该名称必须解析到 Headscale 可达的 IP(即对应 server_url)。证书和账号凭据存在 tls_letsencrypt_cache_dir。相对路径相对于配置文件所在目录。
挑战类型:只支持 HTTP-01(默认)和 TLS-ALPN-01。
- HTTP-01:Headscale 需在 80 端口可达,默认监听所有本地 IP 的 80 端口。可用
tls_letsencrypt_listen改,但 Let’s Encrypt 只连 80,需额外转发。适合非 root 用户或不能setcap的场景。 - TLS-ALPN-01:Headscale 监听
listen_addr,Let’s Encrypt 只连 443,需额外转发。
技术说明
Headscale 用 autocert(Go 库)通过 Let’s Encrypt 做 ACME 验证:
- 证书有效期 3 个月。
- 剩余 30 天或更少时才尝试续期。
- 续期尝试随机间隔 30–60 分钟。
- 跳过或成功续期时无日志输出。
检查证书到期:浏览器打开看,或用 openssl 远程检查。
autocert 日志:如 missing server name 或 host not configured in HostWhitelist,通常是对 IP 或错误主机名的无效请求。这些日志来自 autocert 库,不是 Headscale 本身。
补充:
- 生产环境强烈建议启用 TLS,否则客户端可能拒绝连接或出现安全警告。
- 用反向代理终止 TLS 时,Headscale 可关自带 TLS,但要配
trusted_proxies。- 证书续期不用管,autocert 会自动处理,你只要保证 80 或 443 端口可达。
- 证书要包含完整链,不然 Android 等客户端会拒。
- 自签证书客户端可能不信任,需要手动加信任或(不推荐)禁用验证。
6. Policy(策略)
Headscale 实现了 Tailscale 大部分策略功能,包括基于 ACL 和 Grants 的访问控制,以及 Tailscale SSH。限制见下。
Headscale 用与 Tailscale 相同的 huJSON 格式。默认不加载策略 = 允许所有节点间流量。 启用需在配置文件设 policy.path。
改策略后需重载:sudo systemctl reload headscale 或 sudo kill -HUP $(pidof headscale)。重载后 Headscale 会记录策略处理结果。
参考 Tailscale 策略文档:policy file、ACLs、Grants。
入门
支持 ACL 和 Grants。推荐用 Grants,ACL 已被 Tailscale 视为 legacy,不再有新功能。
- Allow All:定义策略文件但省略
"acls"或"grants"段,默认允许所有。{} - Deny All:
"grants"为空数组。{ "grants": [] } - 更多示例见 Tailscale 文档。
限制
- 不支持 device postures 及相关段(
postures、srcPosture)。 - 不支持 IP sets。
- 只支持部分 Autogroups。
Autogroups
autogroup:internet:经出口节点访问互联网,只能用于目的地。autogroup:member:所有成员。autogroup:tagged:所有至少有一个 tag 的设备。autogroup:self:源和目的地是同一用户的设备,不含标签设备,只能用于目的地。autogroup:nonroot:Tailscale SSH 规则中允许访问除 root 外的任意用户,只能用于 SSH 规则的users字段。autogroup:danger-all:解析为所有 IP(0.0.0.0/0和::/0),包括 Tailscale IP 范围外的,只能作为源。
节点属性
支持的节点属性:
drive:access、drive:share:Taildrive 支持。nextdns:<profile>、nextdns:no-device-info:NextDNS 集成,需在配置里设 NextDNS 为全局解析器。magicdns-aaaa:在本地 MagicDNS 解析器100.100.100.100上响应 AAAA 查询。disable-ipv4:为特定节点禁用 IPv4,可绕过 CGNat 冲突。randomize-client-port:为 WireGuard 流量分配随机端口,而非默认 41641。disable-captive-portal-detection:禁用自动 captive portal 检测。
网络级策略选项
randomizeClientPort:为 WireGuard 流量分配随机端口,而非默认 41641。
Headscale 也允许把策略存在数据库里,通常只有用 Web 界面时才需要。
补充:
- 默认无策略 = 允许所有流量,多用户环境这是安全隐患,别长期这样。
- 策略文件支持热重载,改完不用重启,这是它的一大优点。
- 格式与 Tailscale 兼容,可直接参考 Tailscale 文档。
- 常见用法:限制谁能访问谁、谁能用出口节点、谁能用子网路由、Tailscale SSH 规则。
- Grants 比 ACL 新,建议新配置直接用 Grants。
- 策略写太严是常见故障原因之一,排障时可以临时放宽验证。
7. DNS
Headscale 支持 Tailscale 大部分 DNS 功能。DNS 设置配在 dns 段。
设置额外 DNS 记录
可通过 MagicDNS 提供额外 DNS 记录,两种方式:
- 静态:配置文件的
dns.extra_records,启动时处理,改动需重启。 - 动态:
dns.extra_records_path指向 JSON 文件,Headscale 持续监视变化。适合运行时增删改,或脚本生成。
典型用例:同一主机上用反向代理(如 NGINX)跑多个应用,比如 Prometheus 监控栈,用 http://grafana.myvpn.example.com 代替 http://host:3000。
注意:
dns.extra_records_path要指向 JSON 文件。- 脚本生成时排序键、输出稳定,Headscale 用校验和检测变化,稳定输出避免无谓处理。
用 DNS 查询工具验证记录是否正确。
可选:配置反向代理,示例中的 NGINX 片段用于不带端口访问内部监控服务。
补充:
- MagicDNS 让节点用主机名互访,不用记 IP,这是 Tailscale 体验的核心之一。
- 还可配全局 DNS 解析器、搜索域、split DNS。
- 验证可用
dig/nslookup,或tailscale dns status --all。- 动态记录适合配合自动化脚本,比如容器启动后自动注册 DNS。
8. DERP
DERP(Designated Encrypted Relay for Packets)用于无法直连时中继流量。Headscale 提供嵌入式 DERP 服务器。
配置
DERP 设置配在 derp 段,下面只用部分设置,全部选项见示例配置。
启用嵌入式 DERP:默认禁用,需启用。还应配 Headscale 的公网 IPv4 和 IPv6 地址以提高稳定性。DERP 还需额外端口,除中继外还用 STUN(udp/3478)帮助客户端发现公网 IP 和 NAT 穿透。检查 DERP 连通性确认。
移除 Tailscale 的 DERP 服务器:启用后 Headscale 的嵌入式 DERP 会加到 Tailscale 提供的免费 DERP 列表。想只用嵌入式,禁用默认 DERP 地图加载。
单点故障警告:移除 Tailscale DERP 意味着只剩一个 DERP 服务器,是单点故障,可能影响连通性。移除前先验证嵌入式 DERP 可用。
自定义 DERP 地图:用专用 YAML 文件,可修改通过 URL 获取的 DERP 地图,或提供自己的 DERP 服务器。免费 DERP 按 region ID 组织,可把某 region ID 设为 null 显式禁用。示例 derp.yaml 可禁用纽约(region ID 1),或引用两个自定义 region(ID 900、901)各一个自定义 DERP 服务器,每个提供 tcp/443 HTTPS 中继、tcp/80 captive portal 检查、udp/3478 STUN。全部选项见 DERPMap、DERPRegion、DERPNode 定义。可独立启用嵌入式 DERP 并自动加到自定义地图。
验证客户端:DERP 访问可限制为 tailnet 成员,未知客户端拒绝中继。Tailscale 的 derper 有两个参数:
-verify-client-url指向 Headscale 的/verify端点(如https://headscale.example.com/verify)。客户端连接时 DERP 查询 Headscale 是否允许。-verify-client-url-fail-open控制 Headscale 不可达时的行为,默认允许访问。
检查 DERP 连通性
- 显示 DERP 地图:
tailscale debug derp-map - 检查嵌入式 DERP 连通性:
tailscale debug derp headscale
更多 DERP 指标和信息见 metrics 和 debug 端点。
限制
- 嵌入式 DERP 不能用于 Tailscale 的 captive portal 检查,因为不支持 tcp/80 的
/generate_204。 - 没有速度或吞吐优化,主要目的是协助节点连通性。
补充:
- DERP 是兜底中继:能直连就走直连,不能才走 DERP。
- 启用嵌入式 DERP 需开放 udp/3478 和 tcp/443。
- 别急着关 Tailscale 官方 DERP,官方明确警告单点故障。先确认自己的能用再说。
- DERP 只管连通性,不做速度优化,别当高速通道。
tailscale netcheck能看到各 DERP 的延迟,帮助判断连通性。
9. API
Headscale 提供 HTTP REST API 和 gRPC 接口,用于集成 Web 界面、远程控制、自定义工具。
两者都需要有效 API key。创建(默认 90 天过期):
headscale apikeys create
保存输出,无法再次获取。丢失就过期旧的、建新的。
headscale apikeys list
headscale apikeys expire --prefix <PREFIX>
REST API
- 端点:
/api/v1,如https://headscale.example.com/api/v1 - 文档:
/swagger - 版本:
/version - 认证:
Authorization: Bearer <API_KEY>
在 /swagger 看你自己服务器的 API 文档。
gRPC
用于从远程机器用 headscale 二进制控制实例。
前提:
- 工作站运行
headscale(任意支持平台) - Headscale 服务启用 gRPC
- gRPC 端口(默认 50443)放行
- 远程访问需 TLS 加密连接
- API key
设置远程控制:
- 从 GitHub release 下载
headscale二进制,版本与服务器一致。 - 放到 PATH,如
/usr/local/bin/headscale。 chmod +x /usr/local/bin/headscale。- 在服务器创建 API key。
- 通过最小 YAML 配置或环境变量提供连接参数,让
headscale连远程而非本地。 - 测试:
headscale nodes list。
代理后面:gRPC 远程端点可放反向代理后(如 Nginx),与 Headscale 同端口。非官方支持,NixOS 示例见文档。
故障排查:
- 版本一致
- gRPC 端口放行
- TLS 证书有效可信
- 无受信证书时:加信任,或设
cli.insecure: true/HEADSCALE_CLI_INSECURE=1(不推荐)
补充:
- REST API 适合集成 Web UI、写脚本、自动化。
- API key 创建后只显示一次,务必保存。丢了只能删了重建。
/swagger是开发集成的好入口,能直接看到所有端点和参数。- gRPC 用于远程用
headscale命令控制服务器,版本必须一致。- 自签证书时要么加信任,要么(不推荐)禁用验证。
10. Tags
Headscale 支持 Tailscale tags。详见 Tailscale tag 文档。
Tags 可在节点注册时应用:
--advertise-tags,见 Web 认证的标签设备- 带标签的预认证密钥
管理员可用 Headscale CLI 或 API 管理 tags。
常用操作
管理节点 tags:
headscale nodes list
headscale nodes tag -i 1 -t tag:server,tag:prod
至少一个 tag,多个用逗号分隔。
个人节点 → 标签节点:
headscale nodes tag -i <NODE_ID> -t <TAG>
节点归 tagged-devices 用户所有。
标签节点 → 个人节点:
tailscale up --login-server <URL> --advertise-tags= --force-reauth
headscale auth register --user <USER> --auth-id <AUTH_ID>
旧 tag 全部移除,节点归指定用户。
补充:
- Tags 是服务型节点的核心机制,配合 policy 做细粒度控制。
- 标签节点在策略里用
tag:xxx引用,适合表达「服务器」「生产环境」等语义。- 转回个人节点需要
--force-reauth并重新批准,旧标签会被清空。- Tags + 策略是 Headscale 做细粒度访问控制的主要方式。
11. Reverse proxy(反向代理)
⚠️ 社区文档:非 Headscale 作者维护,未经开发者验证,可能过时或漏步骤。
同一服务器跑多个应用、复用外部 IP 和端口(通常 tcp/443)时有用。
配置
取决于你要用哪些功能。注意端口使用部分,了解 Tailscale 客户端期望什么。示例只覆盖 HTTP 和 HTTPS,STUN 等需直接暴露或只在 localhost。
WebSocket:Tailscale 客户端用自定义协议(Tailscale Control Protocol)与控制服务器通信。反向代理必须支持 WebSocket,并处理两个特殊点:
- 用 POST 方法升级 WebSocket 连接。
Upgrade头的值是tailscale-control-protocol。
TLS:Headscale 可不用 TLS,交给反向代理。配置:
server_url: https://<SERVER_NAME>
tls_cert_path: ""
tls_key_path: ""
启动时 Headscale 会记录 WRN listening without TLS but ServerURL does not start with http://,这是预期的,表示反向代理负责终止 TLS。
受信任代理:Headscale 忽略 True-Client-IP、X-Real-IP、X-Forwarded-For,除非请求的 TCP peer 匹配 trusted_proxies。设为反向代理连接的 CIDR:
trusted_proxies:
- 127.0.0.1/32
- ::1/128
反向代理负责替换客户端传来的这些头。Headscale 按顺序取第一个有效 IP:True-Client-IP → X-Real-IP → X-Forwarded-For。
限制
- 反向代理增加复杂度,需正确处理 Tailscale 控制协议。先不用代理测试再提 issue。
- STUN(嵌入式 DERP)需公开
udp/3478。 - gRPC(远程控制)可能无法代理。
各代理配置
基础 Headscale 配置(假设:443 HTTPS、代理终止 TLS 并重定向 HTTP、同主机、metrics 和 gRPC 不代理走 localhost):
server_url: https://<SERVER_NAME>
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
trusted_proxies:
- 127.0.0.1/32
- ::1/128
tls_cert_path: ""
tls_key_path: ""
- Apache:
ProxyPass / http://127.0.0.1:8080/ upgrade=any(upgrade=any必需,转发Upgrade头不是WebSocket的流量) - Caddy:自动证书、强制 HTTPS、代理 WebSocket
- Cloudflare:不支持,Cloudflare 不支持 Tailscale 协议所需的 WebSocket POST
- Envoy:需加
upgrade_type: tailscale-control-protocol - Istio:同 Envoy,用 EnvoyFilter 加
upgrade_type: tailscale-control-protocol - Nginx:
proxy_http_version 1.1、设Upgrade/Connection、proxy_buffering off
补充:
- 核心难点就是 POST 升级 WebSocket,很多代理默认不认。
- Caddy 最省心,证书和 WebSocket 都自动处理。
- 先无代理跑通再加代理,便于定位问题。
- 别忘了
/generate_204,客户端的连通性检测。- 代理必须替换客户端传来的
True-Client-IP、X-Real-IP、X-Forwarded-For,否则可能被伪造。- gRPC 和 STUN 一般不走代理,让它们走 localhost 或单独端口。
12. Web UI
⚠️ 社区贡献:非 Headscale 作者维护。
Headscale 不提供内置 Web 界面,用户可自选。
可用选项:
- headscale-ui:Web 前端
- HeadscaleUi:静态管理 UI,无需后端
- Headplane:受 Tailscale 启发的高级前端
- headscale-admin:简单现代的 Web 界面
- ouroboros:面向用户管理自己设备,而非管理员
- unraid-headscale-admin:Unraid 用,支持本地(docker exec)和 API 模式
- headscale-console:基于 WebAssembly 的客户端,支持 SSH、VNC、RDP,可选自助服务
- headscale-piying:支持可视化 ACL 配置
- HeadControl:Go + HTMX 极简管理仪表板
- Headscale Manager:Android 版
- Headscale UI:在线及自托管
支持可在 Discord 的 web-interfaces 频道咨询。
补充:
- 都是社区项目,非官方维护,质量活跃度参差。
- 都通过 REST API 交互,先建 API key。
- 用前评估项目活跃度、安全性、权限范围。
- Web UI 不改变 Headscale 核心行为,只是管理界面。
13. Tools(工具)
⚠️ 社区贡献:非 Headscale 作者维护。
第三方工具、客户端库、脚本集合:
- headscale-operator:Kubernetes Operator
- tailscale-manager:动态管理 Tailscale 路由通告
- headscalebacktosqlite:从 PostgreSQL 迁回 SQLite
- headscale-pf:基于 Jumpcloud 或 Authentik 的用户组填充
- headscale-client-go:Headscale HTTP API 的 Go 客户端
- headscale-zabbix:Headscale 服务的 Zabbix 监控模板
- tailscale-exporter:用 Headscale API 提供网络级指标的 Prometheus 导出器
补充:
- 用前评估维护状态。
tailscale-exporter+ Prometheus 适合监控。headscale-client-go适合二次开发。headscale-operator适合 K8s 环境。
14. Debug(调试与故障排查)
Headscale 和 Tailscale 提供调试和自省能力,帮助定位问题。另见 Tailscale 故障排查指南。
Tailscale 客户端
- 本地网络状况:
tailscale netcheck - 客户端状态:
tailscale status --json - DNS 状态:
tailscale dns status --all - 客户端日志:
tailscale debug daemon-logs - 客户端 netmap:
tailscale debug netmap - 测试 DERP 连接:
tailscale debug derp headscale - 更多:
tailscale debug --help
Headscale
应用日志:debug 和 trace 级别可获取更多信息。
log:
level: debug
数据库日志:数据库 debug 模式记录所有查询,需应用日志级别为 debug 或 trace。
database:
debug: false
log:
level: debug
Metrics 和 debug 端点:可自省 Go 运行时信息、内存统计、已连接节点、待处理注册、活动策略、过滤器、SSH 策略、当前 DERPMap、Prometheus 指标。
保持私有:监听地址和端口由
metrics_listen_addr配置,默认 localhost:9090。保持在内网,别暴露到互联网。 设metrics_listen_addr: null可完全禁用。
查询指标:http://localhost:9090/metrics,调试概览:http://localhost:9090/debug/。指标可从 localhost 外查询,但 debug 接口有额外保护。
访问方式:
- 直接访问:在 Headscale 服务器上
curl http://localhost:9090/debug/ - SSH 端口转发:
ssh <HEADSCALE_SERVER> -L 9090:localhost:9090,本地浏览器打开http://localhost:9090/debug/ - 调试密钥:环境变量
TS_DEBUG_KEY_PATH指向密钥文件,请求带debugkey参数,如http://<IP>:9090/debug/?debugkey=<DEBUG_KEY>
补充:
- 排查顺序:客户端状态 → 网络状况 → DERP 连通性 → Headscale 日志 → 数据库 → 策略。
tailscale netcheck快速看 NAT 类型和 DERP 延迟。debug/trace日志信息量大,排障后记得调回。- debug 端点含敏感信息(节点、策略、DERPMap),务必只在内网开。
- 常见故障:IP 转发没开、
server_url不匹配、TLS 证书问题、反向代理不支持 WebSocket、策略过严。- metrics 端点可接 Prometheus + Grafana 做长期监控。
15. 附录:常用命令速查
| 功能 | 命令 |
|---|---|
| 校验配置 | headscale configtest |
| 创建用户 | headscale users create <USER> |
| 列出用户 | headscale user list |
| 批准节点 | headscale auth register --user <USER> --auth-id <AUTH_ID> |
| 创建预认证密钥 | headscale preauthkeys create --user <USER_ID> |
| 列出节点 | headscale nodes list |
| 列出路由 | headscale nodes list-routes |
| 启用路由 | headscale routes enable -r <ROUTE_ID> |
| 管理标签 | headscale nodes tag -i <ID> -t <TAG> |
| 创建 API 密钥 | headscale apikeys create |
| 重载策略 | sudo systemctl reload headscale |