私有化、去中心化、安全自由:使用Docker部署Headscale实现自托管VPN服务

大家好,我是一名从一线打拼出来的老运维,十多年折腾在系统维护、故障抢修、上线发布、运维管理一线,踩过不少坑,也总结了不少实战经验。如果你喜欢这类技术文章,欢迎关注 + 转发支持!
大家如果有问题,也可以问问我的智能助手,有可能在以往的文章找到答案哦:有问必答助手
1️⃣ 引言
由于网友的强烈需求,本文将专门介绍如何通过Docker来搭建Headscale,实现自托管的私有VPN服务。随着网络安全和隐私保护的重要性日益提高,越来越多的人希望能够在自己的网络环境中搭建一个完全私有、去中心化的VPN,而不依赖于第三方的云服务或公网IP。
本文将探讨如何使用Headscale来搭建一个自托管的私有VPN服务,完全摆脱外部服务依赖,真正实现去中心化的网络架构。Headscale是一个轻量级的Tailscale兼容控制服务器,提供与Tailscale相同的高效和安全的连接方式,但通过自托管,你将拥有更高的控制权和数据隐私保障。需要注意的是,由于Headscale本身不提供图形化界面,本文的操作将通过命令行进行,适合具有一定技术能力的用户。
2️⃣ 什么是Headscale?
Headscale 是一个自托管的Tailscale控制服务器。它允许用户无需依赖Tailscale官方的控制服务器,即可使用Tailscale协议建立虚拟私有网络(VPN)。Headscale为那些需要自主管理网络并且希望完全控制数据隐私的用户或企业提供了一个便捷的解决方案。
3️⃣ 什么是Tailscale?
Tailscale 是一种基于WireGuard的VPN解决方案,旨在简化设备之间的网络连接。它通过自动管理网络规则、配置、密钥交换和路由,提供一个高度可用且简单的VPN服务。用户可以快速、轻松地通过Tailscale将设备连接到一个安全的私人网络,无需配置复杂的路由器或VPN服务。
4️⃣ 为了解决什么痛点?
Tailscale 极大简化了传统VPN的部署和管理,然而,它的控制服务器托管在Tailscale官方的云端,这可能导致一些企业或个人用户对隐私和控制的担忧。Headscale 解决了这个痛点,通过允许用户自托管控制服务器,确保了数据隐私,并可以完全控制网络流量。
5️⃣ Headscale的设计目标
Headscale的设计目标是:
-
自托管: 用户可以选择将Headscale部署在自己的服务器上,确保控制权和数据隐私。
-
兼容性: 完全兼容Tailscale客户端,用户可以无缝过渡或混合使用Tailscale和Headscale。
-
易于部署: 使用Docker和docker-compose进行简便的部署,节省运维时间。
-
适应小型企业或个人用户: 通过简化配置和管理,使得中小型企业和个人用户也能使用类似企业级VPN的解决方案。
6️⃣ 架构图

架构图核心说明:
-
- 客户端层:所有终端设备(PC / 手机 / 服务器)需安装 Tailscale 客户端,通过 HTTPS/gRPC 与 Headscale 通信(需指定 --login-server 指向自建 Headscale 地址)。
-
- 网络层(可选):反向代理(如 Nginx)可统一处理 TLS 证书、端口转发;防火墙需开放 Headscale 服务端口(如 443/8443)。 -- 本文演示不使用反向代理
-
- Headscale 服务端:
-
核心是 API 服务,处理客户端请求;身份认证模块 验证节点合法性(如预共享密钥、API Key);网络配置模块 管理 ACL(访问控制列表)、路由规则;依赖 数据库 存储节点信息、网络配置(支持 SQLite 轻量部署或 PostgreSQL 生产部署);DERP 客户端模块 对接 DERP 服务器,处理 P2P 连接失败场景。服务端只参与授权,不参与节点的数据传输。
-
- 辅助服务层: -- 本文演示不安装
-
Headscale-UI:通过 Headscale API 提供可视化管理(需填入 API Key 和 Headscale URL);DERP 服务器:当客户端间无法直接 P2P 连接(如严格 NAT)时,作为中继转发数据(支持自建或使用公共 DERP 节点)。
7️⃣ 服务端的部署
-
- 准备环境:
-
具有公网IP的服务器,家庭若有公网IP的服务器也可以充当服务端。安装Docker和docker-compose。配置域名和SSL证书(可选,用于增强安全性)。
-
- 创建headscale工作目录
mkdir -p ./headscale/{config,lib,run}
cd ./headscale -
- 下载config.yaml,并拷贝至./headscale/config下
修改以下配置:
实验不启用TLS配置,server_usr建议实际生产使用域名,DNS修改为了阿里DNS。
server_url: http://43.192.99.228:8282
listen_addr:0.0.0.0:8282
metrics_listen_addr:0.0.0.0:9090
grpc_listen_addr:0.0.0.0:50443
tls_cert_path:""
tls_key_path:""
nameservers:
global:
-223.5.5.5
-223.6.6.6-
- 使用docker-compose部署Headscale: 创建一个docker-compose.yml文件,内容如下:
services:
headscale:
image:headscale/headscale:stable
restart:unless-stopped
container_name:headscale
ports:
-"0.0.0.0:8282:8282"
-"0.0.0.0:9090:9090"
volumes:
-./config:/etc/headscale
-./lib:/var/lib/headscale
-./run:/var/run/headscale
command:serve
headscale-ui:
image:ghcr.io/gurucomputing/headscale-ui:latest
restart:unless-stopped
container_name:headscale-ui
ports:
# - 8443:8443
-8181:8080-
headscale默认监听8080端口,我修改为了8282,因为我使用的aws服务器,发现8080端口是不通的。
-
这个yaml中,安装了headscale-ui,界面可以打开,可以用于管理用户配置,由于实验中没有使用反向代理,所以本文不介绍headscale-ui的使用。
headscale-ui参考图:

-
- 启动服务: 运行 docker-compose up -d 启动Headscale服务、headscale-ui服务。
-
- 查看日志:
[root@ip-172-31-6-116 container-config]# docker logs --follow headscale
2025-08-30T04:27:11Z INF Opening database database=sqlite3 path=/var/lib/headscale/db.sqlite
2025-08-30T04:27:11Z INF Using policy manager version: 2
2025-08-30T04:27:11Z INF Starting Headscale commit=474ea236d0c6d393dbcf7baa98da240ad20c1b66 version=0.26.1
2025-08-30T04:27:11Z INF Clients with a lower minimum version will be rejected minimum_version=v1.62.0
2025-08-30T04:27:12Z INF listening and serving HTTP on: 0.0.0.0:8282
2025-08-30T04:27:12Z INF listening and serving debug and metrics on: 0.0.0.0:9090-
- 验证headscale是否可用
[root@ip-172-31-6-116 container-config]# curl http://127.0.0.1:9090/metrics
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 2.8389e-05
go_gc_duration_seconds{quantile="0.25"} 4.4694e-05
go_gc_duration_seconds{quantile="0.5"} 4.8366e-05
go_gc_duration_seconds{quantile="0.75"} 5.4168e-05
go_gc_duration_seconds{quantile="1"} 0.000531457
go_gc_duration_seconds_sum 0.010507572
go_gc_duration_seconds_count 185-
- 创建Headscale用户:
docker exec -it headscale headscale users create myfirstuserdocker exec -it headscale headscale users create myseconduser查看用户[root@ip-172-31-6-116 container-config]# docker exec -it headscale headscale users listdocker exec -it headscale headscale users listID | Name | Username | Email | Created1 | | myfirstuser | | 2025-08-30 02:25:032 | | myseconduser | | 2025-08-30 04:55:4
- 创建Headscale用户:
-
myfirstuser用户用于windows:myseconduser用户用于Iphone:
8️⃣ 客户端接入步骤
-
- Windows客户端
下载安装Tailscale Windows客户端
https://tailscale.com/download/windows
打开cmd或Powershell,使用Tailscale登录命令
tailscale login --login-server
C:\Users\home>tailscale login --login-server http://43.192.99.228:8282
To authenticate, visit:
http://43.192.99.228:8282/register/NlEpLSrSxxxxxxxxxxxxxxxxxx
Success.
这里提示使用浏览器打开以上链接需要在headscale server上执行命令,注册这个机器

使用前面创建的myfirstuser用户注册这台Windows机器
docker exec -it headscale headscale nodes register --user myfirstuser --key NlEpLSrXXXXXXXXIYFBTT执行成功后返回windows登录窗口会打印Success.输出。
-
- IOS客户端
从市场下载tailscale,Android请自行下载哦。
-
打开tailscale APP
-
点击右上角账号,选择Log in...
-
点击菜单选项,选择 Use custom coordination server.
-
输入URL,比如:Enter your instance url (http://43.192.99.228:8282)

- 点击继续,和windows一样去headscale服务端去添加机器到网络中。

- 返回手机,就可以看到二台设备都已加入了同一个网络中。

- 在headscale 服务端可以看到二台设备在线。

- 从windows机器上验证一下

C:\Users\home>tailscale ping 100.64.0.2
pong from localhost(100.64.0.2) via DERP(hkg) in 1.402s
pong from localhost(100.64.0.2) via DERP(hkg) in 608ms
pong from localhost(100.64.0.2) via DERP(hkg) in 1.398s
pong from localhost(100.64.0.2) via [2409:891f:68a3:d8c:5183:5723:600a:9e58]:41641 in 40ms
C:\Users\home>tailscale ping 100.64.0.2
pong from localhost(100.64.0.2) via [2409:891f:68a3:d8c:5183:5723:600a:9e58]:41641 in 170ms
C:\Users\home>ping 100.64.0.2
正在 Ping 100.64.0.2 具有 32 字节的数据:
来自 100.64.0.2 的回复: 字节=32 时间=790ms TTL=64
来自 100.64.0.2 的回复: 字节=32 时间=1660ms TTL=64
来自 100.64.0.2 的回复: 字节=32 时间=1223ms TTL=64
来自 100.64.0.2 的回复: 字节=32 时间=640ms TTL=64-
- Linux客户端
-
Linux详细步骤可参考官网,主要变化是指定自己搭建的控制服务器。
tailscale up --login-server <YOUR_HEADSCALE_URL>-
- 验证连接:
-
◾ 成功连接后,设备会自动加入Headscale网络,形成一个虚拟的局域网。
-
◾ 使用 tailscale status 查看当前设备的连接状态。
C:\Users\home>tailscale status
100.64.0.1 desktop-ttb8sge myfirstuser windows -
100.64.0.2 localhost myseconduser iOS -9️⃣ 总结
Headscale为个人用户和小型企业提供了一种灵活且自托管的VPN解决方案,帮助你摆脱对第三方依赖,完全掌控自己的网络架构。通过Docker-Compose部署Headscale,你可以轻松搭建一个安全、稳定的私有VPN,确保设备间的高效、加密通信,并最大化地保障数据隐私。
虽然本文重点介绍了Headscale的基本部署过程,但它的应用远不止如此。通过进一步探索,你可以自行搭建DERP服务器,以解决P2P连接失败的场景,使用图形化界面简化管理步骤,使用安全的https连接访问headscale服务器,或根据具体需求调整路由配置,从而优化网络性能和稳定性。本文展示了Headscale作为VPN解决方案的另一种可能性,它不仅适用于开发和测试环境,也能为个人用户和小型企业提供强有力的支持。
希望通过这篇文章,能够帮助你了解并实现一个完全自由掌控、去中心化的VPN网络,迈出数字隐私保护和安全通信的第一步。
Tips: 在实验过程中,发现ping的耗时比较长,不太稳定,这是什么原因呢?供大家留言探讨!
往期推荐
一键拥有可视化 WireGuard VPN:用 wg-easy 打造你的轻量级远程办公利器
实战系列二:WireGuard 配置优化、密钥管理与客户端接入全攻略
END
重点提醒
🔴 因为有你们的关注和反馈,分享才更有意义 ❤️。
👉 有需要的朋友可以加我 微信:jack_2013L,记得备注暗号【007】,就能入群和更多小伙伴一起交流~
💬 如果你在工作中遇到任何技术问题,欢迎在评论区留言交流,我会挑选一些有代表性的问题,在下篇文章中进行讨论并分享解决思路。
✨ 如果觉得内容对你有帮助,别忘了 关注 + 转发,这样你就不会错过后续的实战分享啦!