自建 Tailscale DERP 与 Peer Relay:阿里云 DNS 踩坑全记录

自建 Tailscale DERP 与 Peer Relay:阿里云 DNS 踩坑全记录
星染自建 Tailscale DERP 与 Peer Relay:阿里云 DNS 踩坑全记录
Tailscale 在国内用起来最大的痛点之一,是 P2P 打洞失败后会掉到官方 DERP 中继。官方 DERP 节点在复杂网络、跨境链路下经常表现为延迟高、吞吐差,甚至几乎不可用。于是就有了自建私有 DERP 的需求:在直连打不通时,至少还能走一条低延迟、可控的中继路径。
1. DERP 是什么,为什么要自建
DERP(Distributed, Encrypted, and Resilient Packet Relay)是 Tailscale 的加密流量中继组件。连接路径大致是:
1 | 优先:直连 / NAT 打洞(P2P) |
官方 DERP 全球有很多节点,但对国内访问并不友好。自建 DERP 的目标很明确:
- 把中继落在自己可控的机房/云厂商
- 降低 relay 场景下的延迟和抖动
- 在 P2P 失败时仍能维持可用的 Tailscale 连接
补充一句:DERP 版本也会跟着 Tailscale 更新。旧版 derper 在中转模式下未必能吃到新版本在吞吐等方面的改进,所以镜像最好能跟着上游版本走。
2. 环境准备
| 项目 | 建议 |
|---|---|
| 系统 | Linux(Ubuntu / Debian 等) |
| 运行时 | 已安装 Docker,docker --version 可正常输出 |
| Tailscale | 宿主机安装并登录 Tailscale 客户端 |
| 网络 | 能出公网;映射端口未被占用,安全组/防火墙放行 |
| 公网 | 有公网 IP 或可被客户端访问的入口(IP + 端口即可) |
宿主机启动 Tailscale 后,一般会在:
1 | /var/run/tailscale/tailscaled.sock |
(部分系统路径为 /run/tailscale/tailscaled.sock)
提供套接字文件。DERP 容器需要挂载这个目录,才能做客户端校验(--verify-clients)。
3. Docker 部署 DERP
3.1 镜像说明
这里使用的是 deepfal/tailscale-derp。作者侧用 GitHub Actions 跟踪上游 derper 版本、打补丁后推到 Docker Hub,直观效果包括:
- 跟进较新的 derper 构建
- 去除域名强制校验相关限制,国内可用 IP + 端口,不必为了 DERP 单独去搞备案域名
- 安全边界仍由客户端校验等机制兜住,宿主机本身要管好权限与暴露面
拉取镜像:
1 | docker pull deepfal/tailscale-derp:latest |
3.2 启动容器
1 | docker run -d \ |
若你机器上套接字在
/var/run/tailscale,把挂载源路径改成对应目录即可。建议挂目录而不是单文件,避免客户端重启后 sock 重建导致容器侧异常。
3.3 参数说明
| 参数 | 含义 |
|---|---|
-d / --restart unless-stopped | 后台运行,异常退出后自动拉起 |
-p 0.0.0.0:59443:36666 | 宿主机 TCP 59443 → 容器 DERP 监听 36666 |
-p 0.0.0.0:3478:3478/udp | STUN 相关 UDP 端口 |
-v /run/tailscale:/var/run/tailscale:ro | 只读挂载 tailscaled 套接字目录,供 --verify-clients 使用 |
-hostname ... | derper 主机名参数(与证书/手工模式配合) |
-a :36666 | 容器内监听地址 |
-certmode manual / -certdir /ssl | 手动证书模式 |
--verify-clients | 校验连接方是否为当前 Tailnet 合法客户端 |
3.4 看日志确认启动
1 | docker logs -f tailscale-derp |
看到类似 DERP server started 的信息即可继续。
3.5 防火墙与安全组
至少放行:
1 | TCP 59443 # 你映射的 DERP 端口,可按需改 |
确认端口未被占用,云厂商安全组与本机 ufw/firewalld 规则一致。
4. 在 Tailscale 中接入自建 DERP
在 Tailscale 管理后台(Access controls / 自定义 derpMap,以你当前控制台入口为准)写入类似配置:
1 | { |
说明:
OmitDefaultRegions: false:保留官方区域,自建作为补充;若只想强制走自建,再考虑改为true(需充分评估可用性)。RegionID建议用 900+ 自定义段,避免和官方区域冲突。InsecureForTests: true适用于 IP + 手动证书/测试场景;生产若配好正规证书,可再收紧。HostName/DERPPort必须和容器实际对外入口一致。
保存后,在客户端执行:
1 | tailscale netcheck |
确认自定义 region 出现且可达。再结合实际跨 NAT 设备互 ping、传文件,看是否从高延迟官方中继切到自建节点。
5. 踩坑:阿里云 ECS 装上 Tailscale 后「没网」
DERP / Peer Relay 往往要落在有公网的云主机上。我在阿里云 ECS 上装完 Tailscale 后,出现了经典但很容易误判的故障:
1 | 安装前:网络正常 |
常见失败命令:
1 | apt update |
但直接 ping 公网 IP 可能正常:
1 | ping -c 3 223.5.5.5 |
说明默认路由未必断了,更可疑的是 DNS。
5.1 现象确认
1 | cat /etc/resolv.conf |
阿里云 VPC 常见:
1 | nameserver 100.100.2.136 |
再对比:
1 | ping -c 3 223.5.5.5 # 往往通 |
结论方向:
1 | 公网三层可达,域名解析链路异常 |
5.2 根因:阿里云 DNS 落在 Tailscale CGNAT 网段
阿里云默认 DNS:
1 | 100.100.2.136 |
属于:
1 | 100.64.0.0/10 |
而 Tailscale IPv4 地址空间也使用 CGNAT 的 100.64.0.0/10。
Linux 上 Tailscale 默认 netfilter-mode=on 时,会加防护规则,大意是:
1 | 允许从 tailscale0 进来的 Tailnet 流量 |
目的是防止物理网卡侧伪造 Tailscale 地址。问题在于:阿里云 DNS 响应包源地址正好是 100.100.2.x,入口却是 eth0 一类物理网卡,于是被规则直接 DROP。
链路示意:
1 | 应用 → DNS 查询 100.100.2.136 |
Tailscale 社区也有针对阿里云 DNS 的同类报告(如 issue #12696)。
5.3 快速验证是不是这个问题
1 | # 看 CGNAT 相关规则(iptables) |
仅用于测试可临时关闭 netfilter 管理:
1 | sudo tailscale set --netfilter-mode=off |
若立刻恢复,再改回:
1 | sudo tailscale set --netfilter-mode=on |
不建议把 netfilter-mode=off 当长期方案:Exit Node、Subnet Router、Peer Relay、Docker 宿主机叠在一起时,防火墙全靠人肉维护风险很大。
5.4 推荐修复:换 DNS + 禁止 Tailscale 接管 DNS
目标:
--accept-dns=false,不接受 Tailnet 下发的 DNS- 把系统 DNS 换成不在
100.64.0.0/10的地址(例如阿里公共 DNS) - 保留
netfilter-mode=on
1 | sudo tailscale set --accept-dns=false |
注意:只关 accept-dns 不够。若 /etc/resolv.conf 仍指向 100.100.2.136/138,响应包照样会被丢。
使用 systemd-resolved 时
1 | systemctl is-active systemd-resolved # 期望 active |
持久化:
1 | sudo mkdir -p /etc/systemd/resolved.conf.d |
确认 stub 链接:
1 | ls -l /etc/resolv.conf |
无 systemd-resolved 时
1 | sudo cp -L /etc/resolv.conf /etc/resolv.conf.bak |
注意 DHCP 续租可能覆盖文件;长期更稳妥的是用网络管理器或阿里云 VPC DHCP 选项集统一配 DNS。
5.5 修复后验收清单
1 | cat /etc/resolv.conf |
期望:
1 | 公网 IP 通 |
6. Peer Relay 配置记录
网络修好后,在同一台阿里云上继续做 Peer Relay,作为严格 NAT 场景下的另一条中继能力(与 DERP 互补,角色不同)。
6.1 节点角色示例
1 | debian |
6.2 标签、Exit Node 与 DNS
优先用 tailscale set,避免 tailscale up 重跑时漏参数:
1 | sudo tailscale set \ |
阿里云环境建议长期保留 --accept-dns=false。
6.3 开启 Peer Relay 端口
1 | sudo tailscale set --relay-server-port=40000 |
若有固定公网 EIP,建议同时声明静态端点:
1 | sudo tailscale set \ |
确认监听:
1 | sudo ss -lunp | grep 40000 |
应看到 tailscaled 在 UDP 40000。
阿里云安全组入方向:
1 | 协议:UDP |
本机 UFW:
1 | sudo ufw allow 40000/udp |
客户端与中继机都需要支持 Peer Relay 的 Tailscale 版本。
6.4 ACL / Grants 示例
1 | { |
要点:
tag:srv:允许使用 Peer Relay 的一侧tag:relay:真正跑中继的节点tailscale.com/cap/relay:下发 Peer Relay 能力
官方说明:不必再单独加一条「允许访问中继机所有 IP/端口」的普通 grant;capability 本身就是分配中继绑定的控制机制。
6.5 验证 Peer Relay
客户端查看候选中继:
1 | # Windows |
1 | # Linux |
正常时类似:
1 | [ |
中继机看会话:
1 | sudo tailscale debug peer-relay-sessions |
抓包 + 造流量:
1 | # 阿里云 |
1 | # Windows |
成功走 Peer Relay 时,tailscale status 连接类型会接近:
1 | active; peer-relay <公网IP>:40000:vni:<ID> |
而不是一直停在类似 active; relay "tok" 的官方 DERP 描述。
7. 整体架构回顾
1 | 客户端 A ←?→ 客户端 B |
| 组件 | 作用 | 注意点 |
|---|---|---|
| 自建 DERP | 替换/补充官方中继路径 | Docker + 宿主机 Tailscale sock;derpMap 配置 |
| Peer Relay | 节点级 UDP 中继能力 | 版本、安全组、grant cap、静态端点 |
| 阿里云 DNS 修复 | 保证装了 Tailscale 还能解析公网域名 | 避开 100.64 段 DNS,保留 netfilter-on |





