返回 · 2026-06-11T07:02:00+00:00
Headscale + DERP 自建结点:低带宽服务器跑控制平面,高带宽服务器跑流量
Headscale + DERP 自建结点:低带宽服务器跑控制平面,高带宽服务器跑流量
楔子
上次折腾 Tailscale 的时候,被一个问题卡了很久:我的小鸡(国内 NAT 机器)带宽实在可怜,跑官方 DERP 结点慢得像便秘,但换成自建 DERP 结点后分流效果立竿见影。后来研究了一下 Headscale + DERP 的组合,发现可以把这个架构拆开——Headscale 控制平面跑在低带宽服务器上,只做信令交互;DERP 结点跑在大带宽服务器上,专门扛流量。这篇文章就是踩坑记录。
原理简单说
Tailscale 的流量有两种走法:
- 直接 P2P:两台机器在同一个 NAT 后面或者能直连,走直连,延迟最低
- DERP 中转:当 P2P 打不通的时候(比如对称 NAT、端口封锁等),流量走 DERP 结点做转发
官方 DERP 结点延迟感人,尤其是国内鸡——绕一圈出去再回来,带宽还被抽了一刀。自建 DERP 的好处是你可以选节点位置,让流量走最优路径。
Headscale 是 Tailscale 控制平面的开源替代品,支持自建 DERP 结点,而且可以把 Headscale 和 DERP 分开部署在不同的机器上。这就很舒服了:
- 小带宽机器:跑 Headscale 控制平面,做信令交换、节点管理、ACL 控制
- 大带宽机器:跑 DERP 结点,走流量,延迟低、带宽足
架构图
┌─────────────────────┐ ┌─────────────────────┐
│ 小带宽服务器 │ │ 大带宽服务器 │
│ (国内 NAT 机) │ │ (有独立 IP 的鸡) │
│ │ │ │
│ Headscale 控制平面 │◄───────►│ DERP 中转结点 │
│ (:443 TLS) │ 信令 │ (:3478 UDP/TCP) │
└─────────────────────┘ └─────────────────────┘
↑ ↑
│ │
Tailscale 客户端 Tailscale 客户端
│ │
手机/电脑/其他节点 手机/电脑/其他节点
第一步:Headscale 控制平面(小带宽机器)
环境
- 系统:Debian 12
- 配置:1C1G 小鸡足够了,信令交换不吃配置
- 域名:
hs.whcself.xyz(已备案)
安装 Headscale
# 下载二进制
wget https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_amd64
sudo mv headscale_0.23.0_linux_amd64 /usr/local/bin/headscale
sudo chmod +x /usr/local/bin/headscale
# 创建用户
sudo useradd -m -s /bin/bash headscale
# 创建配置目录
sudo mkdir -p /etc/headscale
sudo mkdir -p /var/lib/headscale
配置文件
sudo nano /etc/headscale/config.yaml
server_url: https://hs.whcself.xyz
listen_addr: 0.0.0.0:443
metrics_listen_addr: 127.0.0.1:9090
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: "your-email@example.com"
tls_letsencrypt_hostname: "hs.whcself.xyz"
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
allocation: sequential
derp:
server:
enabled: false # 我们用外置 DERP,这儿关掉
urls:
- https://hs.whcself.xyz/derp
log:
format: text
level: info
注意:这里 DERP server 部分
enabled: false,因为我们要单独部署 DERP 结点。urls里填的是 DERP 结点的 URL,后面会用到。
Nginx 反向代理(处理 TLS)
sudo apt install nginx certbot python3-certbot-nginx -y
sudo nano /etc/nginx/sites-available/headscale
server {
listen 80;
server_name hs.whcself.xyz;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name hs.whcself.xyz;
ssl_certificate /etc/letsencrypt/live/hs.whcself.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hs.whcself.xyz/privkey.pem;
location / {
proxy_pass http://127.0.0.1:443;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /derp {
proxy_pass http://127.0.0.1:443;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
sudo certbot --nginx -d hs.whcself.xyz
sudo systemctl enable --now nginx
启动 Headscale
sudo systemctl edit headscale.service
[Unit]
Description=Headscale control plane
After=network.target
[Service]
ExecStart=/usr/local/bin/headscale serve
Restart=always
User=headscale
Group=headscale
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now headscale
创建 namespace 和预共享密钥
# 创建命名空间(相当于 Tailscale 的 tailnet)
headscale namespace create myblog
# 创建预共享密钥(给客户端用)
headscale preauthkey create -n myblog --reusable --expiration 2030-01-01T00:00:00Z
# 记住这个 key,客户端要用
第二步:DERP 结点(大带宽机器)
环境
- 系统:Debian 12
- 配置:2C4G 或者更好,带宽要足
- 域名:
derp.whcself.xyz(复用备案域名,子域名指向 DERP) - 端口:3478 UDP/TCP(DERP 通信)、443(Health check)
安装 DERP
Tailscale 官方提供了独立的 DERP 二进制,不需要装完整的 Tailscale:
wget https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_amd64
sudo mv headscale_0.23.0_linux_amd64 /usr/local/bin/headscale-derp
sudo chmod +x /usr/local/bin/headscale-derp
DERP 配置文件
sudo mkdir -p /etc/headscale-derp
sudo nano /etc/headscale-derp/config.yaml
listen: 0.0.0.0:3478
privateKeyPath: /etc/headscale-derp/private.key
publicKeyPath: /etc/headscale-derp/public.key
verifyClients: true
backendUrl: https://hs.whcself.xyz
生成密钥对
cd /etc/headscale-derp
sudo /usr/local/bin/headscale-derp keys generate
# 会生成 private.key 和 public.key
Nginx + TLS
DERP 的 WebSocket 健康检查走 443:
sudo nano /etc/nginx/sites-available/derp
server {
listen 80;
server_name derp.whcself.xyz;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name derp.whcself.xyz;
ssl_certificate /etc/letsencrypt/live/derp.whcself.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/derp.whcself.xyz/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3478;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
sudo certbot --nginx -d derp.whcself.xyz
sudo systemctl enable --now nginx
启动 DERP
sudo useradd -m -s /bin/bash headscale-derp
sudo chown -R headscale-derp:headscale-derp /etc/headscale-derp
sudo nano /etc/systemd/system/headscale-derp.service
[Unit]
Description=Headscale DERP relay node
After=network.target
[Service]
ExecStart=/usr/local/bin/headscale-derp run -c /etc/headscale-derp/config.yaml
Restart=always
User=headscale-derp
Group=headscale-derp
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now headscale-derp
第三步:在 Headscale 注册 DERP 结点
回到小带宽服务器,执行:
# 获取 DERP 结点的公钥
cat /etc/headscale-derp/public.key
# 假设是: derp1234567890abcdef...
# 注册到 Headscale
headscale derp register --server-name derp-whcself --public-key derp1234567890abcdef... --hostname derp.whcself.xyz
验证一下:
headscale derp list
第四步:客户端接入
Linux
# 安装 Tailscale(不是 Headscale,是 Tailscale 客户端)
curl -fsSL https://tailscale.com/install.sh | sh
# 使用预共享密钥接入(不暴露用户名密码)
sudo tailscale up --login-server https://hs.whcself.xyz --authkey tskey-auth-key-reusable-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
手机(Android/iOS)
下载 Tailscale 应用,登录方式选 Use another login server,填入 https://hs.whcself.xyz,然后用预共享密钥认证。
踩坑记录
坑一:SSL 证书 chain 不完整
DERP 客户端验证 Headscale 控制平面时,如果证书 chain 不完整,会报错 context deadline exceeded。确保 Let's Encrypt 证书包含完整 chain,或者在 Headscale 配置里指定 tls_letsencrypt_challenge_port: 80。
坑二:复用备案域名的子域名指向问题
备案是针对主域名的,子域名如果指向不同 IP,理论上不算新备案(工信部看的是主域名)。但要注意:
- 同一个备案主体下的子域名指向不同服务器是允许的
- 如果子域名指向其他服务器,部分服务商可能会拦截,需要确保域名已完成ICP备案
- SSL 证书正常申请就行,Let's Encrypt 不管你备案不备案
坑三:NAT 机访问 DERP 延迟高
如果客户端也在 NAT 后面,第一次连接 DERP 可能需要打洞。Headscale 支持 STUN 来检测 NAT 类型:
headscale nodes list # 查看节点列表,确认 DERP 结点注册成功
如果所有节点都显示 offline,检查一下 DERP 结点是否在 3478 端口监听:
ss -ulnp | grep 3478
坑四:DERP 健康检查
DERP 有个 /健康检查 端点,可以用这个命令验证:
curl https://derp.whcself.xyz/health
正常返回 {"healthy": true}。
结尾
这套架构跑下来,小带宽服务器只负责信令,几乎不占流量;大带宽服务器专门走流量,带宽利用率直接拉满。备案域名复用 + Let's Encrypt 自动续期,维护成本几乎为零。
如果你的大带宽鸡延迟比官方 DERP 低很多,尤其适合打游戏或者视频通话场景。
有什么问题欢迎留言。