异地组网老是绕远路?自己搭一个 Tailscale DERP 中继,速度直接起飞
说实话,一开始我觉得 Tailscale 自带的 DERP 节点够用了。直到我把家里的 NAS、办公室的台式机、手机三台设备拉进同一个 tailnet,才发现事情没这么简单:打洞失败的时候,流量全走官方中继,而官方节点基本都在海外,延迟 200ms 起步,传个大文件能急死人。
DERP 是啥?说白了就是 Tailscale 的备用通道——P2P 打洞成功就走直连,打洞失败就靠它中转,数据全程加密,只是路径绕一点。既然是中继,节点当然离自己越近越好。那不如……自己搭一个?
网上自建 DERP 的教程不少,但大多要手动编译、手动写配置,折腾半天。我干脆整理了一套自己的部署方案,顺手把踩过的坑都记下来,给想折腾的朋友省点时间。
准备工作
先列个清单,东西不多:
一台有公网 IP 的服务器,1 核 1G 就够跑。DERP 是轻量 Go 服务,瓶颈在带宽不在 CPU,入门机就行
一个域名(可选但强烈推荐,配 Let’s Encrypt 自动证书,省心)
服务器上装好 Docker 和 Docker Compose
防火墙记得放行:TCP 443(或你自定义的 HTTPS 端口)+ UDP 3478(STUN 用)
部署:一条命令的事
我用的是 GitHub 上的 derper-docker 项目,安装脚本直接下载运行,不用 clone 仓库:
curl -fsSL https://raw.githubusercontent.com/DYS7516461/derper-docker/main/install.sh -o install.sh
bash install.sh
脚本会问你域名、证书方式(自动 Let’s Encrypt 或手动证书)、端口这些,答完自动生成配置、拉镜像、启动容器,全程两三分钟。
不想交互式问答的话,也可以用环境变量一步到位:
export DERPER_INSTALL_NONINTERACTIVE=1
export DERPER_INSTALL_HOSTNAME=derp.example.com
export DERPER_INSTALL_CERT_MODE=letsencrypt
export DERPER_INSTALL_HTTPS_PORT=443
export DERPER_INSTALL_STUN_PORT=3478
bash install.sh
跑完会生成两个文件:.env(容器配置)和 derpMap.hujson(待会要粘进 Tailscale 控制台的东西)。生成的 DERP map 长这样:
"derpMap": {
"Regions": {
"900": {
"RegionID": 900,
"RegionCode": "myderp",
"RegionName": "Custom DERP",
"Nodes": [
{
"Name": "900a",
"RegionID": 900,
"HostName": "derp.example.com",
"DERPPort": 443,
"STUNPort": 3478
}
]
}
}
}
接入 Tailscale
接下来两步:
打开 Tailscale 管理后台,进入 Access Controls(就是策略文件编辑页)
把上面这段
derpMap合并进策略 JSON 顶层,保存
客户端一般几秒到几十秒就能拉到新策略,不用重启。
怎么确认真的通了
最直观的验证:
tailscale netcheck
输出里有一栏 DERP 延迟列表,如果看到你自己的节点出现在里面、延迟还是最低的,说明已经生效。想强制走自己的中继测速也可以:
tailscale ping --derp <对端设备>
踩坑记录(重点)
这部分是我最想写的,都是真金白银换来的教训:
1. 证书权限导致容器无限重启
如果你用宝塔或者自己 openssl 生成的证书,私钥默认权限是 600,只有 root 能读。而容器里的 derper 进程是普通用户跑的,直接 permission denied,容器起来就崩、崩了又起,日志刷屏。解决:chmod o+r 私钥文件。新版 install.sh 已经会自动检测并修复这个坑,但你要是手动部署,千万别忘了。
2. 自签名证书必须带 SAN
用 openssl 随手签个证书、CN 填个域名就以为完事了?Go 1.15 之后直接不认:
x509: certificate relies on legacy Common Name field, use SANs instead
签发的时候记得加这个参数:-addext "subjectAltName=DNS:你的域名"。
3. 测试 HTTPS 别裸连 IP
derper 会校验客户端 SNI。你直接 curl https://服务器IP:443 会看到 cert mismatch 报错,以为服务坏了——其实人家正常工作,用域名访问就行。
4. UDP 端口最容易漏
很多人放行 TCP 443 就完事了,忘了 STUN 还需要 UDP 3478。结果 netcheck 里自己的节点 STUN 状态永远是失败的,排查半天。
最后
自建 DERP 之后,我这边组网体验提升非常明显:打洞失败不再绕地球,延迟从 200ms 掉到 30ms 以内,传文件速度也上来了。折腾一个晚上,值。
如果你还缺一台有公网 IP 的服务器,这几个渠道可以看看(入门机就够,重点是带宽):
项目地址在 GitHub:DYS7516461/derper-docker,安装脚本、Docker 镜像(ghcr.io/dys7516461/derper-docker)都是现成的,amd64 / arm64 都支持,跟着 README 走就行。觉得有用的话,也欢迎赞助一杯咖啡支持持续维护 ☕