ZhiBing's blog(码上看世界) ZhiBing's blog(码上看世界)
首页
  • Linux工具链

    • shell命令
  • 构建

    • CMake
    • Makefile
  • 版本管理

    • Git
    • Github
  • IDE及工具

    • vscode
    • CLion
  • 设计模式

    • 设计原则
  • 编程语言

    • C++
    • Go
    • Python
    • Shell
  • 调试

    • gdb
  • 开发者测试

    • gtest
  • 系统支撑

    • 操作系统
  • 性能优化

    • 编译优化选项
    • perf
    • valgrind
  • 容器

    • Docker
  • 微服务

    • Rancher
  • 其他
  • 随笔
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

ZhiBing Zheng

时间会回答成长
首页
  • Linux工具链

    • shell命令
  • 构建

    • CMake
    • Makefile
  • 版本管理

    • Git
    • Github
  • IDE及工具

    • vscode
    • CLion
  • 设计模式

    • 设计原则
  • 编程语言

    • C++
    • Go
    • Python
    • Shell
  • 调试

    • gdb
  • 开发者测试

    • gtest
  • 系统支撑

    • 操作系统
  • 性能优化

    • 编译优化选项
    • perf
    • valgrind
  • 容器

    • Docker
  • 微服务

    • Rancher
  • 其他
  • 随笔
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • 编程语言

  • 调试

  • 开发者测试

  • 系统支撑

    • 操作系统

      • 内存分区
      • 初识CGroup
    • Headscale 自建组网部署笔记
    • Headscale Docker 容器化部署方案
      • 架构概览
      • 前置条件
      • 端口规划
      • 部署步骤
        • 1. 创建目录结构
        • 2. 生成私钥
        • 3. 配置文件
        • 4. ACL 策略
        • 5. Docker Compose
        • 6. 启动服务
        • 7. ACL 策略加载
        • 8. 创建用户
        • 9. 客户端连接
        • 10. 验证 DERP 中继
      • 证书自动续期
        • 问题
        • 解决方案
        • 续期流程
      • 数据持久化
      • 常用维护命令
      • v0.23.0 → v0.29.1 迁移要点
      • 安全说明
      • 参考链接
  • 性能优化

  • 小技巧

  • 通用领域
  • 系统支撑
兵兵
2026-07-02
目录

Headscale Docker 容器化部署方案

# Headscale Docker 容器化部署方案

基于 Docker Compose 容器化部署 Headscale v0.29.1,集成自建 DERP 中继和 Let's Encrypt TLS 证书,支持证书自动续期。

# 架构概览

┌──────────────────────────────────────────────────────────┐
│                   阿里云 ECS (Docker)                      │
│                                                          │
│  ┌─────────────────────────────────────────────────────┐ │
│  │              headscale container                     │ │
│  │                                                     │ │
│  │   ┌──────────────┐    ┌──────────────────────┐     │ │
│  │   │  API :443    │    │  DERP :443 + STUN    │     │ │
│  │   │  (HTTPS)     │    │  :3478               │     │ │
│  │   └──────┬───────┘    └──────────┬───────────┘     │ │
│  │          │                       │                  │ │
│  │   ┌──────┴───────┐    ┌──────────┴───────────┐     │ │
│  │   │  gRPC :50443 │    │  Let's Encrypt TLS   │     │ │
│  │   └──────────────┘    └──────────────────────┘     │ │
│  └─────────────────────────────────────────────────────┘ │
│                         │                                │
│                    Tailscale 隧道                         │
│           ┌─────────────┼─────────────┐                  │
│      ┌────┴────┐   ┌────┴────┐   ┌────┴────┐            │
│      │ Node A  │   │ Node B  │   │ Node C  │            │
│      │(服务器) │   │ (手机)  │   │(笔记本) │            │
│      └─────────┘   └─────────┘   └─────────┘            │
└──────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 前置条件

项目 要求
服务器 阿里云 ECS,固定公网 IP
操作系统 Ubuntu 20.04+ / CentOS 7+
Docker v20.10+,Docker Compose v2+
TLS 证书 Let's Encrypt 可信证书(acme.sh 自动续期)
安全组 443/TCP、50443/TCP、3478/UDP 已放行

# 端口规划

端口 协议 用途 说明
443 TCP Headscale API + DERP HTTPS API 和 DERP 中继共享同一端口
50443 TCP gRPC 控制面 节点注册和管理
3478 UDP STUN NAT 穿透探测,用于发现公网地址

# 部署步骤

# 1. 创建目录结构

sudo mkdir -p /opt/headscale/{config,data,certs}
cd /opt/headscale
1
2

# 2. 生成私钥

Headscale 需要三把私钥,首次部署前必须生成:

# WireGuard 私钥
docker run --rm headscale/headscale:v0.29.1 \
  headscale generate private-key > /opt/headscale/data/private.key

# Noise 协议私钥(Tailscale v2 认证)
docker run --rm headscale/headscale:v0.29.1 \
  headscale generate private-key > /opt/headscale/data/noise_private.key

# DERP 服务私钥
docker run --rm headscale/headscale:v0.29.1 \
  headscale generate private-key > /opt/headscale/data/derp_server_private.key

# 设置权限
chmod 600 /opt/headscale/data/*.key
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3. 配置文件

创建 /opt/headscale/config/config.yaml:

# ============================================================
# Headscale v0.29.1 容器化配置
# 替换 <YOUR_PUBLIC_IP> 为服务器公网 IP
# ============================================================

# ---- 基础配置 ----
server_url: https://<YOUR_PUBLIC_IP>:443
listen_addr: 0.0.0.0:443
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false
metrics_listen_addr: ""
randomize_client_port: false
disable_check_updates: true

# ---- 密钥路径(容器内路径) ----
private_key_path: /var/lib/headscale/private.key
noise:
  private_key_path: /var/lib/headscale/noise_private.key

# ---- 数据库 ----
database:
  type: sqlite
  sqlite:
    path: /var/lib/headscale/db.sqlite
    write_ahead_log: true

# ---- IP 分配 ----
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48
  allocation: random

# ---- DERP 中继 ----
derp:
  server:
    enabled: true
    region_id: 999
    region_code: "custom-derp"
    region_name: "自建 DERP"
    port: 443
    stun_port: 3478
    stun_listen_addr: "0.0.0.0:3478"
    private_key_path: /var/lib/headscale/derp_server_private.key
    tls_cert_path: /etc/headscale/certs/cert.pem
    tls_key_path: /etc/headscale/certs/key.pem
    ipv4: <YOUR_PUBLIC_IP>
    automatically_add_embedded_derp_region: true
    verify_clients: false
  urls: []
  paths: []
  auto_update: false

# ---- 策略 ----
policy:
  mode: database
  path: /etc/headscale/acl.json

# ---- DNS ----
dns:
  magic_dns: false
  nameservers:
    global:
      - 223.5.5.5
      - 8.8.8.8
  domains: []

# ---- 日志 ----
log:
  format: text
  level: info
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

配置要点说明:

配置项 说明
server_url 客户端连接地址,使用 HTTPS + 443 端口
listen_addr API 和 DERP 共享 443 端口(同一进程)
grpc_listen_addr gRPC 独立端口 50443
database.type: sqlite v0.29.1 字段名(旧版 db_type: sqlite3 已废弃)
policy.mode: database ACL 策略格式,v0.29.1 重构后的新写法
derp.server.tls_cert_path DERP 使用 Let's Encrypt 证书
prefixes 必须配置,否则节点无法分配 IP

# 4. ACL 策略

创建 /opt/headscale/config/acl.json,默认全部互通:

{
  "acls": [
    { "action": "accept", "src": ["*"], "dst": ["*:*"] }
  ]
}
1
2
3
4
5

生产环境建议按需限制节点间访问权限。

# 5. Docker Compose

创建 /opt/headscale/docker-compose.yml:

version: '3.8'

services:
  headscale:
    image: headscale/headscale:v0.29.1
    container_name: headscale
    restart: unless-stopped
    ports:
      - "443:443"           # API + DERP
      - "50443:50443"       # gRPC 控制面
      - "3478:3478/udp"     # STUN
    volumes:
      - ./config:/etc/headscale:ro           # 配置文件(只读)
      - ./data:/var/lib/headscale            # 数据持久化(DB + 密钥)
      - /path/to/certs:/etc/headscale/certs:ro  # TLS 证书(只读)
    command: ["serve"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意事项:

  • command: ["serve"] — entrypoint 已包含 headscale,只需 serve 参数
  • ./data 卷挂载保证容器重建后数据不丢失(数据库 + 三把私钥)
  • 证书目录替换为实际路径

# 6. 启动服务

cd /opt/headscale

# 启动
docker compose up -d

# 查看日志确认无报错
docker compose logs -f headscale
1
2
3
4
5
6
7

启动成功的标志日志:

DERP region 999 started
listening on 0.0.0.0:443
gRPC server listening on 0.0.0.0:50443
1
2
3

# 7. ACL 策略加载

配置中使用 policy.mode: database 模式,需要手动将策略推入数据库:

docker exec headscale headscale policy set /etc/headscale/acl.json
1

验证:

docker exec headscale headscale policy get
1

# 8. 创建用户

# 创建用户
docker exec headscale headscale users create default

# 生成预授权密钥(有效期 30 天,可重复使用)
docker exec headscale headscale preauthkeys create \
  --user 1 --reusable --expiration 720h
1
2
3
4
5
6

输出的密钥格式为 hskey-auth-xxx...,后续客户端连接需要使用。

# 9. 客户端连接

# 安装 Tailscale 客户端
curl -fsSL https://tailscale.com/install.sh | sh

# 连接到自建 Headscale
tailscale up \
  --login-server https://<YOUR_PUBLIC_IP>:443 \
  --authkey <PREAUTH_KEY> \
  --hostname <DEVICE_NAME> \
  --accept-routes \
  --reset
1
2
3
4
5
6
7
8
9
10

关键说明:

  • 使用 https:// 连接(DERP 使用可信证书,无需 --derp-insecure)
  • --reset 用于清除之前的连接状态
  • --accept-routes 接受子网路由

# 10. 验证 DERP 中继

# 检查网络状态
tailscale netcheck

# 验证 DERP 连通性
tailscale ping <对端节点>
1
2
3
4
5

输出应包含自建 DERP 区域信息。

# 证书自动续期

# 问题

Let's Encrypt 证书通常 90 天有效,acme.sh 会自动续期并 reload nginx,但不会自动重启 Docker 容器。

# 解决方案

配置 acme.sh 的续期钩子,在证书更新后自动重启 headscale 容器:

# 查看当前证书配置
acme.sh --list

# 更新续期钩子(替换为实际域名或 IP)
acme.sh --install-cert -d <YOUR_DOMAIN_OR_IP> \
  --reloadcmd "nginx -t && systemctl reload nginx && docker restart headscale"
1
2
3
4
5
6

# 续期流程

acme.sh cron (每日 07:01)
  → 检测证书即将到期(7天短期证书约4天续期)
  → 重新签发证书
  → 安装到证书目录
  → 执行续期钩子:
      1. nginx -t          # 验证 nginx 配置
      2. systemctl reload nginx  # 重载 nginx
      3. docker restart headscale  # 重启容器加载新证书
  → 容器启动时自动加载新证书
1
2
3
4
5
6
7
8
9

# 数据持久化

/opt/headscale/
├── config/
│   ├── config.yaml          # Headscale 配置
│   └── acl.json             # ACL 策略
├── data/
│   ├── db.sqlite            # SQLite 数据库(用户、节点、密钥)
│   ├── private.key          # WireGuard 私钥
│   ├── noise_private.key    # Noise 协议私钥
│   └── derp_server_private.key  # DERP 服务私钥
├── certs/ -> /etc/nginx/ssl/   # TLS 证书(符号链接或挂载)
└── docker-compose.yml       # 容器编排
1
2
3
4
5
6
7
8
9
10
11

重建容器不会丢失数据:

  • ./data 卷持久化数据库和私钥
  • ./config 卷持久化配置
  • 证书通过宿主机目录挂载,续期后自动生效

# 常用维护命令

# ---- 用户管理 ----
docker exec headscale headscale users list
docker exec headscale headscale users create <用户名>

# ---- 节点管理 ----
docker exec headscale headscale nodes list
echo "y" | docker exec headscale headscale nodes delete --identifier <ID>
docker exec headscale headscale nodes expire --identifier <ID>

# ---- 预授权密钥 ----
docker exec headscale headscale preauthkeys create \
  --user <USER_ID> --reusable --expiration 720h

# ---- API 密钥(供 Scale Manager 等 App 使用)----
docker exec headscale headscale apikeys create --expiration 90d

# ---- ACL 策略 ----
docker exec headscale headscale policy get
docker exec headscale headscale policy set /etc/headscale/acl.json

# ---- 容器管理 ----
docker compose logs -f headscale      # 实时日志
docker restart headscale               # 重启
docker compose down && docker compose up -d  # 重建

# ---- 客户端 ----
tailscale status                       # 查看连接状态
tailscale netcheck                     # 检查 DERP 连通性
tailscale ping <对端节点>              # 测试延迟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# v0.23.0 → v0.29.1 迁移要点

如果从旧版本迁移,注意以下字段变更:

旧版 (v0.23.0) 新版 (v0.29.1) 说明
db_type: sqlite3 database.type: sqlite 数据库配置重构
db_path: ... database.sqlite.path: ... 同上
acl_policy_path: ... policy.mode: database + policy.path: ... ACL 格式重构
dns_config: dns: 字段重命名
缺失 noise.private_key_path 必需字段
缺失 prefixes IP 分配范围,必需
缺失 derp.server.stun_listen_addr STUN 监听地址,必需
command: ["headscale", "serve"] command: ["serve"] entrypoint 已含 headscale

# 安全说明

层级 加密方式 说明
DERP 中继 TLS 1.3 Let's Encrypt 证书,客户端信任链完整
WireGuard 隧道 ChaCha20-Poly1305 节点间数据端到端加密
STUN 无加密 仅用于 NAT 发现,不传输业务数据
API HTTPS Let's Encrypt 证书保护

# 参考链接

  • Headscale 官方文档 (opens new window)
  • Headscale GitHub (opens new window)
  • Tailscale DERP 服务器文档 (opens new window)
  • Docker Hub - headscale/headscale (opens new window)
#VPN#Tailscale#Headscale#Docker#容器化
Headscale 自建组网部署笔记
C++编译优化选项

← Headscale 自建组网部署笔记 C++编译优化选项→

最近更新
01
Headscale 自建组网部署笔记
06-29
02
通过公网安全访问 OpenClaw
06-06
03
strace抓取隐藏错误
06-06
更多文章>
Theme by Vdoing | Copyright © 2022-2026 ZhBing Zheng | 粤ICP备2022062743号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式