丢掉向日葵,我用Headscale + DERP 两个Docker 搭了私有Tailnet

2026-07-05 07:48:15 2点赞 13收藏 0评论
自管理 Tailnet 封面自管理 Tailnet 封面

Tailscale 这类组网工具最吸引人的地方,是它把复杂的 WireGuard、NAT 穿透、设备发现、路由下发都做成了“登录一下就能用”。手机、笔记本、NAS、小主机分散在不同网络里,也能像在同一个局域网里一样互相访问。

但方便背后也有一个现实问题:控制面是谁的?中转是谁的?

日常使用官方 Tailscale 没什么问题,体验成熟、省心、客户端也好用。但如果你已经开始把 NAS、家庭服务、远程桌面、密码管理器、开发机、摄像头、旁路由这些东西放进虚拟内网,继续把设备协调和备用中转都交给外部服务,心里多少会有一点别扭。

我这次折腾的目标很明确:不是重新发明 Tailscale,而是尽量把这套网络的关键环节收回自己手里。

  • 控制面:用 Headscale 自己管理。

  • 中转面:用自建 DERP 自己兜底。

  • 客户端:继续用成熟的 Tailscale 客户端。

  • 部署方式:两个 Docker 容器跑在自有 VPS 上。

这样做之后,设备还是用熟悉的 Tailscale 客户端,连接体验也基本不变;不同的是,设备注册、节点发现、路由下发、中转节点,都由自己的服务器控制。

先晒一下我的环境

VPS 上运行的 headscale 与 derper 容器VPS 上运行的 headscale 与 derper 容器

我的 VPS 上现在跑着两个核心容器:

  • headscale/headscale:latest:自管理控制服务器。

  • fredliang/derper:latest:自建 DERP 中转服务器。

截图里还能看到 Vaultwarden 和其他容器,但这篇只看 Headscale 与 DERP。我的思路是:公网 VPS 只负责控制面和必要时的中转,真正的家庭内网资源仍然放在家里,不直接暴露到公网。

这套环境里,外出手机、笔记本、家中 NAS、小主机都登录到自己的 Headscale。能直连时,设备之间直接走 WireGuard;直连失败时,再走自己的 DERP。

tailscale netcheck 显示自建 DERPtailscale netcheck 显示自建 DERP

再看客户端的 tailscale netcheck,这里已经能看到自建 DERP:

Nearest DERP: My DERP DERP latency: - myderp: 13.4ms - homederp: 24.6ms

这说明客户端拿到的 DERP map 里已经包含我自己的节点。它不是只能依赖默认公共中转,而是可以优先使用我指定的中转服务器。

这一步很关键。很多人自建 Headscale 之后,控制面确实私有化了,但 DERP 仍然走默认公共节点。这样也能用,但还没有完成我想要的“自管理闭环”。我更想要的是:协调归我,中转也归我。

拓扑图:两个 Docker 各自负责什么

Headscale 与自建 DERP 拓扑图Headscale 与自建 DERP 拓扑图

把这套网络拆开看,其实并不复杂。

Headscale 是控制面。它负责用户、设备、密钥、节点列表、ACL、DNS、路由发布这些事情。客户端上线时,会找 Headscale 报到;Headscale 告诉它网络里还有哪些设备、应该下发哪些配置。

DERP 是备用中转面。正常情况下,Tailscale 客户端会尽量让两端设备直连,数据包直接在设备之间走。如果两端因为运营商 NAT、公司网络、酒店 Wi-Fi、防火墙策略等原因无法直连,才会退回到 DERP 中转。

这里容易误解的一点是:DERP 不是明文代理。它转发的是已经加密的 WireGuard 数据包,主要解决“两个设备见不到彼此”的连通性问题。DERP 服务器能看到连接元数据和流量大小,但看不到你内网服务里的具体内容。

所以这套架构的边界很清楚:

  • Headscale 管“谁能加入网络、谁能发现谁”。

  • DERP 管“直连失败时怎么转发加密包”。

  • 家中服务继续留在内网,不需要逐个做公网端口映射。

  • 客户端仍然使用官方 Tailscale App,学习成本低。

对家庭用户和小团队来说,这个组合比较舒服:不用自己写 VPN 客户端,也不用把每一个内网服务都放到公网入口前面。

为什么要自建 Headscale + DERP

我自己看重的不是“免费”,而是边界和可控性。

第一,控制面自己掌握。

哪些设备能加入网络、设备名称是什么、哪些路由允许发布、哪些节点应该下线,这些都在自己的 Headscale 里管理。手机丢了,直接删节点;临时接入新设备,发一个短有效期预授权密钥;不用再围绕第三方账号体系去设计家庭内网权限。

第二,中转节点自己掌握。

现实网络环境里,不是所有连接都能顺利打洞。尤其是移动网络、公司网络、校园网、酒店 Wi-Fi、部分运营商大内网,直连失败很正常。自建 DERP 的意义,就是在这些场景下还有一个自己控制的中转点。

第三,公网暴露面更小。

家里有 NAS、开发机、管理后台、远程桌面、媒体库、下载器时,最怕为了方便访问而开一堆端口。用 Tailnet 之后,公网只需要暴露 VPS 上必要的 Headscale / DERP 入口,家中服务不需要逐个站到公网前面。

第四,迁移和维护可预期。

Headscale 的配置、数据库、密钥都在自己机器上。以后换 VPS、换域名、加 DERP 节点、备份恢复,都能按自己的节奏处理。

当然,这不是说官方 Tailscale 不好。官方服务省心、稳定、功能完整,适合大多数人。自建方案更适合已经有 VPS、有 Docker 基础、愿意自己维护网络入口的人。

必要清单

开始之前,我建议先把这些东西准备好。

  1. 一台公网 VPS

最好有固定公网 IPv4。配置不用很高,1 核 1G 也能跑起来;如果你经常通过 DERP 看视频、传大文件,就要更关注带宽和流量包。

  1. 一个域名

建议至少准备两个子域名:

hs.example.com derp.example.com

hs 用来访问 Headscale,derp 用来访问 DERP。后面的示例都用这两个占位域名,实际部署时替换成你自己的。

  1. Docker 与 Docker Compose

这篇按 Docker 部署写。好处是迁移简单,目录结构清楚,后续更新也方便。

  1. HTTPS 证书

Headscale 必须让客户端通过可信 HTTPS 地址访问。可以用 Caddy、Nginx Proxy Manager、Traefik 或其他反代工具签证书。

DERP 一般监听 443/tcp,也要有可用证书。不同 DERP 镜像对证书和环境变量支持略有差异,实际以你选的镜像说明为准。

  1. 防火墙端口

常见端口如下:

443/tcp DERP HTTPS,或反代入口 3478/udp DERP STUN 8080/tcp Headscale 服务端口,建议只监听本机 9090/tcp Headscale metrics/health,建议只监听本机

我更建议把 8080 和 9090 绑定到 127.0.0.1,只让反代访问它。公网入口越少,后面排查和加固越简单。

  1. 客户端设备

手机、笔记本、NAS、小主机安装 Tailscale 客户端即可。Headscale 的好处之一,就是不用自己维护客户端。

部署流程

下面这套流程是我这类家庭自建环境比较容易理解的版本。域名、端口、证书方案可以按自己的情况调整。

第一步:准备目录

在 VPS 上准备目录:

mkdir -p /opt/headscale/config mkdir -p /opt/headscale/data mkdir -p /opt/derper/certs

后面最需要备份的是 Headscale 的配置、数据库和密钥。DERP 通常更像无状态中转,迁移成本低一些。

第二步:写 Headscale 配置

新建 /opt/headscale/config/config.yaml,核心配置可以先这样理解:

server_url: https://hs.example.com listen_addr: 0.0.0.0:8080 metrics_listen_addr: 0.0.0.0:9090 noise: private_key_path: /var/lib/headscale/noise_private.key database: type: sqlite sqlite: path: /var/lib/headscale/db.sqlite derp: server: enabled: false urls: [] paths: - /etc/headscale/derp.yaml dns: magic_dns: true base_domain: tailnet.example.com

几个重点:

  • server_url 要写客户端能访问到的 HTTPS 域名。

  • database 用 SQLite 对家庭和小团队够用,记得备份。

  • derp.urls: [] 表示不加载默认 DERP 列表。

  • derp.paths 指向自己的 DERP map。

  • magic_dns 打开后,设备之间可以用名称访问,日常更顺手。

第三步:写自建 DERP map

新建 /opt/headscale/config/derp.yaml:

regions: 901: regionid: 901 regioncode: myderp regionname: My DERP nodes: - name: myderp-1 regionid: 901 hostname: derp.example.com derpport: 443 stunport: 3478

regionid 自己选一个不冲突的数字即可。regioncode 和 regionname 会体现在客户端检测结果里,前面截图里的 My DERP 就是这个含义。

如果你有多台 VPS,也可以放多个 region,让客户端按延迟自动选。

第四步:写 Docker Compose

创建 docker-compose.yml:

services: headscale: image: headscale/headscale:latest container_name: headscale restart: unless-stopped command: serve volumes: - /opt/headscale/config:/etc/headscale - /opt/headscale/data:/var/lib/headscale ports: - "127.0.0.1:8080:8080" - "127.0.0.1:9090:9090" derper: image: fredliang/derper:latest container_name: derper restart: unless-stopped environment: - DERP_DOMAIN=derp.example.com - DERP_ADDR=:443 - DERP_STUN=true - DERP_VERIFY_CLIENTS=false ports: - "443:443/tcp" - "3478:3478/udp" volumes: - /opt/derper/certs:/app/certs

这里有两个实际注意点。

第一,如果你的 VPS 上 443/tcp 已经被 Caddy、Nginx 或其他反代占用了,DERP 不能再直接绑定 443。这时要么换部署方式,要么把 DERP 独立到另一台 VPS,要么确认你的反代能正确转发 DERP 所需流量。

第二,DERP_VERIFY_CLIENTS=false 代表 DERP 不校验客户端身份,配置简单。更严格的做法是开启客户端校验,但要额外打通 DERP 与 Headscale 的校验关系,复杂度会上升。家庭自用可以先跑通,再逐步收紧。

启动服务:

docker compose up -d docker ps

看到 headscale 和 derper 都是 Up,第一阶段就完成了。

第五步:反代 Headscale

Headscale 的 8080 已经绑定到本机,所以需要用反代把 https://hs.example.com 转进去。

Caddy 示例:

hs.example.com { reverse_proxy 127.0.0.1:8080 }

如果你用 Nginx Proxy Manager 或 Traefik,逻辑一样:外部 HTTPS 域名进来,转发到 127.0.0.1:8080。

第六步:创建用户和预授权密钥

创建用户:

docker exec -it headscale headscale users create jiang

创建预授权密钥:

docker exec -it headscale headscale preauthkeys create --user jiang --reusable --expiration 24h

家庭环境里,我喜欢用短有效期 key。加设备的时候临时生成,用完过期,不把长期可用密钥到处保存。

第七步:客户端接入

Linux、macOS 或部分命令行环境可以这样接入:

tailscale up --login-server=https://hs.example.com --auth-key=你的预授权密钥

手机端也可以使用 Tailscale 客户端,只是入口位置因系统版本和客户端版本不同会有差异。核心就是把登录服务器指向自己的 Headscale,而不是默认官方控制面。

第八步:按需发布内网路由

如果只是让几台设备互访,让每台设备都装 Tailscale 客户端就行。

如果你想在外面访问整个家庭网段,比如家里的 NAS、路由器管理页、开发机、打印机,可以在家里找一台常开设备作为子网路由:

tailscale up --login-server=https://hs.example.com --auth-key=你的预授权密钥 --advertise-routes=192.168.119.0/24

然后在 Headscale 里批准这条路由。之后,外出设备连上 Tailnet 后,就能访问 192.168.119.0/24 里的内网资源。

这一步要谨慎。发布整个网段很方便,但权限也更大。建议先从单台服务或小网段开始,确认没问题再扩大范围。

验证步骤

这类网络服务不能只看“网页能打开”。我一般按下面几层检查。

1. 看容器状态

docker ps

确认 headscale 和 derper 都在运行,端口映射符合预期。我的第一张截图就是这个状态。

2. 看 Headscale 健康状态

在 VPS 本机执行:

curl http://127.0.0.1:9090/health

能返回健康状态即可。这个端口不建议开放公网。

3. 看节点列表

docker exec -it headscale headscale nodes list

接入过的手机、笔记本、NAS、小主机都应该能看到。

4. 看 DERP map 是否下发

在客户端执行:

tailscale netcheck

重点看输出里有没有自己的 DERP:

Nearest DERP: My DERP DERP latency: - myderp: xx ms

如果这里能看到,就说明 Headscale 已经把自建 DERP 配置发给客户端。

5. 看设备之间是否能互通

tailscale status tailscale ping 目标设备名

能直连时,体验最好;不能直连时,也应该能通过 DERP 打通。两个结果都正常,区别只是路径不同。

6. 验证内网服务没有直接暴露公网

这是最容易忽略的一步。

断开 Tailnet,用普通外网访问你的家庭公网 IP、VPS IP、域名,不应该能打开家中内网服务。路由器上也不应该保留一堆历史端口映射。

连接 Tailnet 后,再访问内网服务:

http://192.168.119.x:端口

如果断开 Tailnet 看不到,连接 Tailnet 才能看到,说明安全边界才是对的。

7. 验证子网路由

如果发布了家庭网段,可以在外出设备上测试:

ping 192.168.119.1 curl -I http://192.168.119.x:端口

能访问说明路由生效。如果不通,先检查 Headscale 里是否批准了路由,再看家中路由设备是否开启转发。

安全加固建议

自建不是一键变安全。你把控制权拿回来,也意味着维护责任在自己身上。

  1. VPS 只开放必要端口

公网入口越少越好。Headscale 的服务端口和健康检查端口尽量只监听本机,公网只暴露确实需要的 443/tcp 和 3478/udp。

  1. SSH 使用密钥登录

禁用密码登录,限制 root 登录,系统及时更新。VPS 是这套网络的入口,基础安全不能省。

  1. 预授权密钥短有效期

新设备接入时临时生成 key,用完过期。设备加完后,长期可复用 key 就不要留着。

  1. 丢失设备及时移除

手机丢了、笔记本卖了、临时测试机不用了,及时在 Headscale 里删节点。

  1. 配置和数据库定期备份

至少备份:

/opt/headscale/config /opt/headscale/data

这里面包含配置、数据库和私钥。没有备份,VPS 出问题后恢复会比较麻烦。

  1. 子网路由按需开放

不要一上来就把所有家庭网段都发布出去。能只接入单台设备,就不要开放整个网段;确实需要网段访问,再配合 ACL 做限制。

  1. 不要神化 DERP

DERP 解决的是连通性,不是匿名性。自建 DERP 仍然会暴露连接时间、来源 IP、流量大小等元数据,只是中转节点在自己手里,数据内容仍由 WireGuard 加密保护。

使用感受

搭好之后,日常使用其实很轻。

手机、笔记本、NAS、小主机都在同一个 Tailnet 里。人在外面时,打开 Tailscale,家里的服务就像仍在局域网内一样;能直连就直连,不能直连就走自己的 DERP。对使用者来说,变化不大;对管理员来说,控制边界完全不一样。

我比较喜欢这套方案的一点,是它没有把问题复杂化。客户端还是成熟的 Tailscale,底层还是 WireGuard,Headscale 负责替代控制面,DERP 负责兜底中转。真正需要维护的,就是 VPS 上这两个 Docker 和一份配置。

如果你只是想简单远程访问,官方 Tailscale 已经足够好。

但如果你已经有 VPS,也在意“控制面归谁、中转归谁、内网入口放在哪里”,Headscale + 自建 DERP 就很值得折腾。它不是为了炫技,而是让这张私有网络的关键开关尽量握在自己手里。

我的理解是:家庭自建服务的安全感,不只是服务跑在自己机器上,还包括访问路径也能被自己理解、管理和关闭。

用 Headscale 管设备,用 DERP 做自己的中转,再配合 Tailscale 客户端使用,这就是我目前觉得比较平衡的一种私有化组网方案。

作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

展开 收起
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

相关文章推荐

更多精彩文章
更多精彩文章
最新文章 热门文章
13
扫一下,分享更方便,购买更轻松