Derper 搭建
derper 是Tailscale/headscale 自建的中转节点,用来组网解决公共节点打洞成功率太低和延迟问题。
自建 DERP 节点
序
之前用一台国外 VPS 配合 sing-box 开过 DERP。和公共 DERP 相比,带宽能跑满,但因为线路和 NAT 环境问题,UDP 打洞一直没成功。
后来换成国内云主机,改用官方 derper 二进制重新部署。
如果机器上没有现成的 Nginx 和证书体系,优先用更简单的官方直跑方案:
-a :443-http-port 80-certmode letsencrypt
我最终采用的方案:Nginx 监听 443,后端 derper 监听 12443,证书由 Nginx 管理,derper 用 manual 模式读取证书。
最终架构
流量路径如下:
| |
对应关系:
443/tcp:DERP 客户端入口,走 Nginx3478/udp:STUN 打洞,直达derper12443/tcp:后端derper监听端口,只给本机 Nginx 用,阿里云防火墙策略里面不对公网放行
--verify-clients 用来防止其他人白嫖
如果开启 --verify-clients:
- DERP 机必须安装并接入
tailscaled derper会通过本机tailscaled判断客户端是不是自己 tailnet 的成员
端口规划
至少要确认这些端口:
443/tcp:放行3478/udp:放行80/tcp:只在你需要 Nginx 做 ACME 或 HTTP 跳转时放行12443/tcp:不要在云安全组里放行
这样外部只能通过 Nginx 进来,但 STUN 还能正常工作。
前提条件
假设:
- 系统是
Debian 12 - 域名是
derp.example.com - 域名已经解析到 VPS 公网 IP
- 证书由 Nginx 或其他现有流程维护
如果准备开启 --verify-clients,还需要:
- 安装
tailscaled - 让这台 DERP 机加入正确的 tailnet
- 最好给它打上
tag:derp
如果机器上启用了 Tailscale,且 apt update 超时,优先确认不是 DNS 或私网镜像源问题。长期建议:
| |
安装 Go 和 derper
验证 Go:
| |
如果没装 Go,自行安装到 /usr/local/go 后,补 PATH:
| |
创建运行目录:
| |
安装 derper:
| |
如果国内网络太慢:
| |
验证:
| |
安装并接入 Tailscale
如果要用 --verify-clients,DERP 机必须先入网:
| |
检查状态:
| |
证书准备
如果你已经有 Nginx 管理的证书,例如:
/etc/nginx/ssl/derp/cert.pem/etc/nginx/ssl/derp/key.pem
那么 derper 使用 -certmode manual 时,不会直接认 cert.pem 和 key.pem 这种名字。它要求证书文件名必须和主机名一致:
derp.example.com.crtderp.example.com.key
因此可以用软链接映射:
| |
这是这次排障里最关键的坑之一:
- 开了
-certmode manual - 却没配
-certdir - 或者证书文件名不匹配主机名
结果就是 derper 直接启动失败,Nginx 对后端只能拿到 502 Bad Gateway。
derper.service
最终采用的 systemd 配置如下:
/etc/systemd/system/derper.service
| |
这里有几个关键点:
User=root:开启--verify-clients时,这样最省事,避免本地tailscaled.sock权限问题-a :12443:不要写成127.0.0.1:12443-http-port -1:关闭derper自己的 HTTP 监听-stun-port 3478:STUN 端口是纯数字,不要写成:3478-certmode manual+-certdir:让derper使用你已经准备好的证书-verify-clients:限制只允许自己 tailnet 的客户端使用
启动:
| |
Nginx 反代配置
示例:
/etc/nginx/sites-available/derp
| |
启用并检查:
| |
这次排障确认了几个容易错的点:
proxy_pass必须是https://127.0.0.1:12443,不能写成http://proxy_ssl_server_name on和proxy_ssl_name derp.example.com最好一起带上proxy_buffering off建议开启,DERP 这种长连接/流式转发场景更稳
tailnet policy 和 derpMap
示例:
这里的重点是:
DERPPort写443,因为客户端实际连的是 Nginx,不是后端12443STUNPort还是3478- 开启
--verify-clients时,不要把 ACL 写得过死,至少先保证tag:derp能“看见”允许使用它的节点
ACL 写太严时,tailscale ping 和节点探测都出现异常。先跑通,再慢慢收紧规则更稳妥。
如果需要 ping,别忘了 ACL 里要考虑 icmp。
验证方法
服务状态
| |
端口监听
| |
期望结果:
12443/tcp在监听3478/udp在公网地址上监听,而不是只绑在127.0.0.1
域名访问
| |
Tailscale 状态
| |
如何判断:
- 看到自定义 DERP 区域,说明
derpMap生效 - 看到
relay "sz"之类信息,说明 DERP 可作为中转保底 - 看到
direct,说明 UDP 打洞成功,已经不是纯 DERP 中转
这次排障里最关键的结论
502 Bad Gateway不等于真的是 443 被拦了 很多时候只是 Nginx 能起来,但后端derper没起来。 先查:
| |
如果 12443 没监听,优先看 derper 启动参数和证书。
manual模式下,证书目录和文件名必须对 这次最开始的502,根因之一就是:
derper开了-certmode manual- 但没找到正确的证书
要么缺
-certdir,要么证书不是按主机名命名。
- Nginx 反代
derper时,上游必须走 HTTPSderper在这套配置下是 TLS 服务。如果 Nginx 写成:
| |
那就属于协议对不上,最后可能得到 400 或 502。
-a 127.0.0.1:12443会把 STUN 一起绑到回环地址 这是这次踩的另一个大坑。 如果把-a绑到127.0.0.1,很多版本的derper会让3478/udp也只监听回环地址。结果就是:
- 网页可能正常
- DERP 中转可能正常
- 但
direct很难成功,因为外部客户端根本打不到 STUN 因此最终保留:
| |
然后通过云安全组不开放 12443/tcp 来补安全。
derpMap要指向 443,不是 12443 客户端连的是:
| |
所以 DERPPort 必须写 443。
--verify-clients依赖本机tailscaled的可见范围 如果日志里出现:
| |
优先检查:
- DERP 机是否已经加入正确的 tailnet
tag:derp是否配置正确- ACL / grants 是否让 DERP 机能看到这些客户端
如果只是临时排障,也可以先去掉
-verify-clients,等网络和反代都跑通再加回来。
- 海外节点访问异常时,要分清是配置问题还是安全组/线路问题 如果外地或海外节点完全打不到你的自建 DERP: 先在远端做两类测试:
| |
然后回头检查:
- 云安全组是否放行了
443/tcp - 云安全组是否放行了
3478/udp 12443/tcp是否没有对公网放行- 是否确实存在跨境线路抖动或区域性阻断
安全建议
这一套最终的安全边界是:
- 公网开放
443/tcp - 公网开放
3478/udp - 公网不开放
12443/tcp derper开启--verify-clients
这样即使 derper 进程监听了 :12443,外部也很难直接打到它。
如果你只是临时测试:
- 可以先不启用
--verify-clients - 先把
Nginx -> derper、derpMap、STUN跑通 - 最后再加访问控制
最终判断标准
满足以下条件就算部署完成:
derper.service是active (running)curl -I https://derp.example.com正常返回3478/udp对外可达tailscale netcheck能看到自定义 DERP 区域- 需要中转时能走到自建 DERP
- 网络允许时能出现
direct - 未授权客户端会被
--verify-clients拒绝