
《从零开始:无域名部署完全私有化 Tailscale(Headscale + 自建 DERP + Web UI)保姆级教程》
🎯 私有化部署 Headscale + 自建 DERP + Web UI(无域名、国内友好、生产级安全)
✅ 无需域名 | ✅ 国内网络友好 | ✅ 防踩坑指南 | ✅ 生产级安全配置
📌 适用人群:个人/家庭/企业私有组网、远程办公、内网穿透、替代商业 Tailscale
🧩 技术栈:Docker + Headscale + Derper + Web UI + Caddy(无域名 HTTPS 可选)
🕒 最后更新:2025年9月11日
💻 测试环境:Ubuntu 22.04 LTS + Docker 24.0.7 + Docker Compose v2.23.0
🎯 一、为什么选择私有化部署 Tailscale?
Tailscale 是一款基于 WireGuard 的零配置组网工具,但其官方服务依赖 controlplane.tailscale.com
和全球 DERP 中继节点,存在:
- ❌ 数据出境风险(企业合规问题)
- ❌ 国内访问延迟高(尤其 DERP 节点在国外)
- ❌ 企业版收费昂贵($6/月/用户)
✅ Headscale + 自建 DERP + Web UI = 完全私有化、无依赖、无费用、高性能内网穿透方案。
🧰 二、准备工作
✅ 你需要:
- 一台具有公网 IP 的云服务器(国内/海外均可,推荐 2C4G 起)
- 开放以下端口(安全组/防火墙):
TCP 8080
—— Headscale API(客户端注册)TCP 8000
—— Web UI(可选,建议内网访问)TCP 445, 446
+UDP 3478
—— 自建 DERP 服务(STUN + 中继)
- 安装好
Docker
和Docker Compose
(教程略,可参考官方文档) - 一个终端 SSH 连接工具(如 Xshell、Tabby、VSCode Remote)
🚫 本教程不依赖域名,所有访问均通过 IP + 端口完成。
📂 三、目录结构规划(建议在 /opt/headscale
下操作)
/opt/headscale
├── container-config/ # Headscale 配置文件
├── container-data/ # 持久化数据(数据库、密钥)
│ └── data/
├── headscale-repo/ # Headscale 源码(用于构建镜像)
├── headscale-ui/ # Web UI 源码
├── ip_derper # ip_derper 源码
└── docker-compose.yml # 服务编排文件
🧱 四、第一步:部署自建 DERP 服务(中继节点)
DERP(Detoured Encrypted Routing Protocol)是 Tailscale 用于 NAT 穿透和流量中继的协议。自建 DERP 可确保流量不出内网。
4.1 克隆并构建 Derper 镜像
cd /opt/headscale
git clone https://kkgithub.com/yangchuansheng/ip_derper.git
cd ip_derper
修改源码 —— 禁用证书域名校验:
vim tailscale/cmd/derper/cert.go
找到 getCertificate 函数,注释掉以下三行:
func (m *manualCertManager) getCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
// if hi.ServerName != m.hostname {
// return nil, fmt.Errorf("cert mismatch with hostname: %q", hi.ServerName)
// }
...
}
⚠️ 安全提醒:此修改会降低 TLS 安全性,仅建议在完全私有、受控网络环境中使用。 生产环境建议配置合法域名 + 有效证书(如 Let’s Encrypt)。
在 Dockerfile
中添加源 apk(加速构建)👇
# build modified derper
RUN cd /app/tailscale/cmd/derper && \
go env -w GO111MODULE=on && \ #👈需添加这👈
go env -w GOPROXY=https://goproxy.cn,direct && \ #👈两行代码👈
CGO_ENABLED=0 /usr/local/go/bin/go build -buildvcs=false -ldflags "-s -w" -o /app/derper && \
cd /app && \
rm -rf /app/tailscale
我们继续修改下方相关的端口信息👇
# ========= CONFIG =========
# - derper args
ENV DERP_ADDR :23446 # 需要修改的http端口
ENV DERP_HTTP_PORT 23445 # 需要修改的https端口
ENV DERP_HOST=127.0.0.1
ENV DERP_CERTS=/app/certs/
ENV DERP_STUN true
ENV DERP_VERIFY_CLIENTS false
# ==========================
保存后执行构建指令👇
docker build -t ip_derper:1.86.2 .
🖥️ 五、第二步:部署 Headscale Web UI
Web UI 用于可视化管理节点、用户、ACL,大幅提升操作效率。
5.1 克隆 Headscale-ui 源码
cd /opt/headscale
git clone https://wget.la/https://github.com/gurucomputing/headscale-ui.git
cd headscale-ui/docker/production
5.2 给 Derper 创建配置文件 derper.json
cd /opt/headscale/headscale-ui/docker/production
vim derper.json
添加如下内容👇(请替换 公网服务器 IP
为你的真实公网 IP)
{
"Regions": {
"901": {
"RegionID": 901,
"RegionCode": "Myself",
"RegionName": "Myself Derper",
"Nodes": [
{
"Name": "901a",
"RegionID": 901,
"DERPPort": 23446,
"HostName": "公网服务器 IP",
"IPv4": "公网服务器 IP",
"InsecureForTests": true
}
]
}
}
}
📌
HostName
和IPv4
填写你的公网服务器 IP。
5.3 修改 Dockerfile(复制 derper.json + 换源 + 安全用户)
编辑 headscale-ui/docker/production/Dockerfile
(大约在文件第 57 行)👇
在 COPY --from=build /staging/${PROJECT_NAME}/build /web
后添加:
COPY ./derper.json /web/derper.json #👈需要添加此代码
#👇将RUN apk add --no-cache caddy替换为
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk add --no-cache caddy
5.4 修改 Caddyfile(关键!API 反向代理)
编辑 headscale-ui/docker/production/Caddyfile
:
:{$HTTP_PORT} {
redir / /web
uri strip_prefix /web
file_server {
root /web
}
# 👇👇👇 必须添加!否则 UI 无法调用 API 👇👇👇
reverse_proxy /api/v1/* http://headscale:8080 {
header_up Host {host}
}
}
# 如果不需要 HTTPS,注释以下部分(自签名证书)
:{$HTTPS_PORT} {
redir / /web
uri strip_prefix /web
tls internal
file_server {
root /web
}
reverse_proxy /api/v1/* http://headscale:8080 {
header_up Host {host}
}
}
💡 为什么必须加
/api/v1/*
代理?
Web UI 默认会请求http://宿主机IP:8000/api/v1/status
等接口。
若不配置反向代理,请求会直接打到 Caddy,而 Caddy 不认识这些 API,返回 404。
通过reverse_proxy
将/api/v1/*
转发给headscale:8080
,实现前后端分离。
5.5 修改 1-image-build.sh
文件位于 headscale-ui/docker/production/scripts/
#!/bin/sh
set -x
apt-get update && apt-get install -y git
git clone https://github.com/gurucomputing/headscale-ui.git ${PROJECT_NAME} #👈我修改了
cd ${PROJECT_NAME}
git checkout ${CHECKOUT_BRANCH}
npm config set registry https://registry.npmjs.org #👈我添加了
npm install
sed -i "s/insert-version/${VERSION}/g" ./src/routes/settings.html/+page.svelte
npm run build
5.6 构建 UI 镜像
cd /opt/headscale/headscale-ui/docker/production
docker build -f dockerfile -t headscale-ui:time25.08.23 .
🧠 六、第三步:部署 Headscale 核心服务
6.1 拉取源码并生成配置
cd /opt/headscale
git clone https://github.com/juanfont/headscale.git headscale-repo
cp ./headscale-repo/config-example.yaml ./container-config/config.yaml
6.2 修改 container-config/config.yaml
server_url: http://你的公网IP:8080 # 👈 必须是公网IP!
listen_addr: 0.0.0.0:8080 # 👈 监听所有接口
prefixes:
v4: 100.64.0.0/10
# v6: fd7a:115c:a1e0::/48 # 👈 无 IPv6 环境请注释
derp_map:
urls:
- http://headscale-ui:8000/web/derper.json # 👈 自建 DERP 映射
# - https://controlplane.tailscale.com/derpmap/default
randomize_client_port: true # 👈 防蹭网,随机端口
6.3 优化构建镜像(Go 换源加速)
编辑 headscale-repo/Dockerfile.integration
👇
# RUN go install github.com/go-delve/delve/cmd/dlv@latest
# 将这行👆代码 替换为下列代码👇
RUN echo "=== Installing delve with domestic proxy ===" && \
go env -w GOPROXY=https://goproxy.cn,direct && \
go env -w GOSUMDB=off && \
go env -w GO111MODULE=on && \
go install github.com/go-delve/delve/cmd/dlv@latest
6.4 构建 Headscale 镜像
cd /opt/headscale/headscale-repo
docker build -f Dockerfile.integration -t headscale:v0.26.1 .
🐳 七、第四步:编写 docker-compose.yml
version: "3.9"
services:
headscale:
image: headscale:v0.26.1
container_name: headscale
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
volumes:
- ./container-config:/etc/headscale
- ./container-data/data:/var/lib/headscale
entrypoint: headscale serve
networks:
- headscale_net
ports:
- "8080:8080"
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
headscale-ui:
image: headscale-ui:time25.08.23
container_name: headscale-ui
restart: unless-stopped
environment:
- HTTP_PORT=8000
- HTTPS_PORT=8443
networks:
- headscale_net
ports:
- "8000:8000" # 👈 仅用于初始配置,完成后建议注释掉!
ip-derper:
image: ip_derper:1.86.2
container_name: ip-derper
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
network_mode: "host"
networks:
headscale_net:
driver: bridge
⚠️ 注意:
image: headscale:v0.26.1
—— 不是官方镜像!
🚀 八、启动服务
cd /opt/headscale
docker-compose up -d
查看日志:
docker-compose logs -f headscale
docker-compose logs -f headscale-ui
🔐 九、初始化 Web UI 配置
- 浏览器访问:
http://你的公网IP:8000
- 点击界面中的 Settings
- 获取 API Key:
docker exec -it headscale headscale apikey create --expiration 3650d # 3650d代表天数👍
# 输出示例:INCSHXxXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- 在 Web UI 中:
- Headscale API Key: 粘贴上面生成的 key
- Headscale URL: 留空(默认使用
http://宿主机IP:8000/api/v1
,因 Caddy 已反向代理) - 点击 Test Server Settings → 应显示 “Connection successful!”
🧩 原理说明:
UI 会请求http://宿主机IP:8000/api/v1/apikey
,Caddy 将其转发给headscale:8080
,Headscale 验证 API Key 成功,返回状态。
👥 十、创建用户与添加节点
10.1 创建用户(两种方式)
方式一:Web UI
- 在 Web UI 点击 User View
- 输入用户名创建用户
- 访问
http://IP:8080/windows
获取登录链接 - 复制
"nodekey:xxxxxxxxx"
内容 - 在 Web UI Device View 添加设备
方式二:命令行
docker exec -it headscale headscale users create myuser
10.2 生成节点注册命令
docker exec -it headscale headscale --user myuser node register --output-qr
或访问:http://你的公网IP:8000/windows
(或其他平台),复制命令到客户端执行。
10.3 批准节点(如未开启 auto_approval)
docker exec -it headscale headscale --user myuser node list # 查看节点 ID
docker exec -it headscale headscale --user myuser node move --node-id 1 --to-user myuser
或在 Web UI 的 Nodes 页面点击 Approve。
🛡️ 十一、安全加固建议
关闭 Web UI 公网暴露:编辑
docker-compose.yml
,注释掉ports: - "8000:8000"
,通过 SSH 隧道访问:ssh -L 8000:localhost:8000 user@your-server
本地浏览器访问
http://localhost:8000
启用 HTTPS(自签名):取消
Caddyfile
中 HTTPS 部分的注释,Caddy 会自动生成证书。配置 ACL:在
config.yaml
中指定acl_policy_path
,限制节点间访问。
🧩 十二、客户端配置(以 Windows 为例)
下载 Tailscale 官方客户端
退出登录(如已登录官方账号)
执行命令:
tailscale up --login-server=http://你的公网IP:8080
浏览器会打开,粘贴注册命令或扫码,完成注册。
📊 十三、验证与测试
- Web UI 查看节点状态(Online)
- 两台设备互相 ping
100.64.x.x
地址 - 检查 DERP 路径:
tailscale netcheck
- 查看流量是否走自建 DERP:
tailscale status --active
🆘 十四、常见问题排查
问题 | 解决方案 |
---|---|
Web UI 显示 “Failed to fetch” | 检查 Caddyfile 是否配置 /api/v1/* 反向代理 |
客户端注册失败 | 检查 server_url 是否为公网 IP,防火墙是否放行 8080 |
DERP 无法连接 | 检查 Derper 是否使用 network_mode: host ,端口 3478/445 是否开放 |
节点无法互相 ping | 检查 auto_approval 或手动批准,检查 ACL 策略 |
🎉 十五、恭喜你!完全私有化 Tailscale 部署成功!
你已拥有:
- ✅ 无域名、无依赖的私有组网服务
- ✅ 自建 DERP 节点,国内低延迟
- ✅ Web UI 可视化管理
- ✅ 企业级安全配置(防蹭网、手动审批、ACL)
📚 Headscale 常用命令速查
Namespace
headscale namespace list # 查看所有的namespace
headscale namespace create myspace # 创建namespace
headscale namespace destroy myspace # 删除namespace
headscale namespace rename myspace newspace # 重命名namespace
Node
headscale node list # 列出所有的节点
headscale node ls -t # 列出所有的节点,同时显示出tag信息
headscale -n myspace node ls # 只查看namespace为myspace下的节点
headscale node delete -i<ID> # 根据id删除指定的节点(id可用node list查询)
# 如 headscale nodes delete -i=2
headscale node tag -i=2 -t=tag:test # 给id为2的node设置tag为tag:test
Route
headscale routes list -i=3 # 列出节点3的所有路由信息
headscale routes enable -i=3 -r=192.168.10.0/24
# 将节点3的路由中信息为192.168.10.0/24的设置为true,
# 这样除了虚拟内网ip,原先的内网ip网段为192.168.10的也能访问了
📥 后续可扩展功能
- 配置 Exit Node(让其他设备通过此服务器上网)
- 配置 Subnet Router(访问服务器所在内网)
- 集成 Prometheus + Grafana 监控流量
- 使用 PostgreSQL 替代 SQLite(高可用)
📌 本文为全网最详细、最防踩坑、最易上手的 Headscale 私有化部署教程。
如需 PDF/Markdown 源码/一键脚本,请留言告知。
欢迎点赞、收藏、转发给需要的朋友!
✅ 教程完结,部署成功!
有任何问题,欢迎在评论区留言,我会一一解答。