Tailscale 自建 DERP 中继服务器
DERP(Designated Encrypted Relay for Packets)是 Tailscale 的中继与连通性组件。它主要承担两件事:
- 协助节点打洞,尽量建立直连
- 直连失败时,作为中继节点转发流量
两种部署方式:
- Docker:上手快,依赖容器生态,换镜像即可升级
- 非 Docker:系统服务 + 二进制,更接近系统级运维,替换二进制即可升级
快速导航
完成部署后:§6 ACL 配置 → §7 客户端重连 → §8 测试验收
1. 部署参数
文中使用占位符表示需要替换的参数。后续步骤中出现这些占位符时,请替换为你的实际值。
| 占位符 | 说明 | 示例值 |
|---|---|---|
<VPS_IP> |
VPS 公网 IP | xxx.xxx.xxx.xxx |
<DERP_TCP_PORT> |
DERP TCP 端口 | 13477 |
<STUN_UDP_PORT> |
STUN UDP 端口 | 13478 |
<REGION_ID> |
自定义 DERP 区域 ID | 900 |
<REGION_CODE> |
自定义 DERP 区域代码 | myderp |
<RELAY_HOSTNAME> |
DERP 服务器的 Tailscale IP(通过 tailscale status 查看第一列) |
100.x.x.x |
💡 提示:如果你想先完整跑一遍,可把
<VPS_IP>、<DERP_TCP_PORT>、<STUN_UDP_PORT>先替换为xxx.xxx.xxx.xxx、13477、13478。
2. 准备工作
放行安全组与防火墙端口:
<DERP_TCP_PORT>/tcp:DERP 服务端口<STUN_UDP_PORT>/udp:STUN 服务端口
⚠️ 注意:需同时检查云厂商安全组和系统防火墙两层规则。
2.1 可选:切换软件包镜像源
国内网络下包管理器拉取较慢时,按系统切换镜像源:
Debian / Ubuntu
# 备份原始源
cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 替换为阿里云镜像(以 Ubuntu 22.04 为例,其他版本替换 jammy)
sed -i 's|http://archive.ubuntu.com|https://mirrors.aliyun.com|g' /etc/apt/sources.list
apt update
RHEL / CentOS / Rocky
# 以 Rocky Linux 9 为例
sed -i 's|https://dl.rockylinux.org|https://mirrors.aliyun.com/rockylinux|g' /etc/yum.repos.d/rocky*.repo
dnf makecache
Alpine {#apk-mirror}
cp /etc/apk/repositories /etc/apk/repositories.bak
# 版本号需与你的 Alpine 一致,通过 cat /etc/alpine-release 查看
cat > /etc/apk/repositories << 'EOF'
https://mirrors.aliyun.com/alpine/v3.22/main
https://mirrors.aliyun.com/alpine/v3.22/community
EOF
apk update
3. Docker 部署
3.1 安装 Docker 与 Compose
| 系统 | 安装命令 |
|---|---|
| Debian / Ubuntu | apt update && apt install -y docker.io docker-compose-plugin |
| RHEL / CentOS / Rocky | dnf install -y docker docker-compose-plugin |
| Alpine | apk add docker docker-compose |
ℹ️ 说明:Alpine 下 Compose 通常是 V1(
docker-compose),如需 V2 可通过二进制安装docker-compose-plugin。
3.2 启用 Docker 服务
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu / RHEL | systemctl enable --now docker |
| Alpine | rc-update add docker boot && service docker start |
验证安装:
docker --version
# Debian/Ubuntu/RHEL 使用:
docker compose version
# Alpine 使用:
docker-compose --version
3.3 Docker 镜像加速(可选)
拉取 Docker 镜像较慢时配置,写入后永久生效:
mkdir -p /etc/docker
cat > /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://dockerproxy.com",
"https://docker.m.daocloud.io"
]
}
EOF
重启 Docker:Debian / Ubuntu / RHEL 执行 systemctl restart docker,Alpine 执行 service docker restart。
💡 提示:低配置 VPS 可在
daemon.json中追加以下参数:{ "registry-mirrors": ["..."], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "max-concurrent-downloads": 2 }
log-opts:限制单个日志文件最大 10MB、最多保留 3 个,防止磁盘被日志撑满max-concurrent-downloads:限制同时下载层数为 2,降低内存和带宽占用
3.4 创建 docker-compose.yml
所有系统通用,将占位符替换为实际值(参考 §1):
services:
derper:
image: ghcr.io/yangchuansheng/ip_derper:latest # 目前上游未发布正式版本标签,使用 latest;升级时重新拉取即可
container_name: derper
restart: unless-stopped
ports:
- <DERP_TCP_PORT>:<DERP_TCP_PORT> # 替换为 DERP 端口,如 13477
- <STUN_UDP_PORT>:3478/udp # 替换为 STUN 端口,如 13478
environment:
- DERP_ADDR=:<DERP_TCP_PORT> # 替换为 DERP 端口,格式为 :<端口号>
- DERP_VERIFY_CLIENTS=true # 开启客户端验证,避免被公网滥用
volumes:
- /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
⚠️ 注意:STUN 容器内部端口固定为
3478/udp,左边是主机映射端口,务必放行对应的主机 UDP 端口。
3.5 启动并验证
| 系统 | 启动命令 | 端口检查命令 |
|---|---|---|
| Debian / Ubuntu / RHEL | docker compose up -d |
ss -tulnp \| grep -E "<DERP_TCP_PORT>\|<STUN_UDP_PORT>" |
| Alpine | docker-compose up -d |
netstat -tulnp \| grep -E "<DERP_TCP_PORT>\|<STUN_UDP_PORT>" |
通用验证:
docker logs derper
4. 非 Docker 部署
ℹ️ 说明:官方 Tailscale 包不包含
derper二进制,需从源码编译。
4.1 系统准备
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu | apt update && apt upgrade -y && apt install -y wget openssl curl netcat-openbsd |
| RHEL / CentOS / Rocky | dnf update -y && dnf install -y wget openssl curl nmap-ncat |
| Alpine | apk update && apk upgrade && apk add wget openssl curl netcat-openbsd |
💡 提示:国内网络下包管理器拉取较慢时,可参考 §2.1 切换软件包镜像源。
4.2 创建目录结构
所有系统通用:
mkdir -p /usr/local/derp/{bin,certs}
4.3 安装 Go 环境
| 系统 | 安装命令 |
|---|---|
| Debian / Ubuntu | apt install -y golang |
| RHEL / CentOS / Rocky | dnf install -y golang |
| Alpine | apk add go |
验证:go version
大陆地区切换下载源(Go 1.13 及以上,所有系统通用):
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
4.4 编译 derper
编译需要内存 >= 2GB:
go install tailscale.com/cmd/derper@latest
cp ~/go/bin/derper /usr/local/derp/bin/
💡 提示:低内存 VPS 编译可能报 OOM,可改用 §4.9 异机交叉编译,完成后回到「§4.5 验证编译结果」继续。
4.5 验证编译结果
chmod +x /usr/local/derp/bin/derper
# 验证是否为静态二进制
ldd /usr/local/derp/bin/derper # 应输出 "not a dynamic executable"
# 验证版本
/usr/local/derp/bin/derper --version
ℹ️ 说明:
--version输出类似1.xx.x-ERR-BuildInfo是正常的(go install编译不含完整构建信息)。
如果遇到 Permission denied,可能是 /usr/local 被挂载为 noexec:
# 检查挂载选项
mount | grep /usr/local
# 如果存在 noexec,复制到其他位置运行
cp /usr/local/derp/bin/derper /root/derper
chmod +x /root/derper
/root/derper --version
确认可执行后,将二进制放回 /usr/local/derp/bin/ 或调整挂载选项。
4.6 生成自签名证书
⚠️ 注意:证书文件名要与
-hostname对应,建议直接使用<VPS_IP>.crt与<VPS_IP>.key。
cd /usr/local/derp/certs
# 将下方所有 <VPS_IP> 替换为你的服务器公网 IP
openssl req -x509 -newkey rsa:2048 -sha256 -days 3650 \
-nodes -keyout <VPS_IP>.key -out <VPS_IP>.crt \
-subj "/CN=<VPS_IP>" \
-addext "subjectAltName=IP:<VPS_IP>"
参数说明:
-keyout <VPS_IP>.key:私钥输出文件,文件名需与-hostname一致-out <VPS_IP>.crt:证书输出文件,文件名需与-hostname一致-subj "/CN=<VPS_IP>":证书通用名称,设为服务器 IP-addext "subjectAltName=IP:<VPS_IP>":SAN 扩展,必须包含 IP-days 3650:有效期 10 年
4.7 创建服务并启动
4.7.1 systemd(Debian / Ubuntu / RHEL)
cat > /etc/systemd/system/derper.service << 'EOF'
[Unit]
Description=Tailscale DERP Server
After=network.target
Wants=network.target
[Service]
User=root
Group=root
# 下方 <VPS_IP>、<DERP_TCP_PORT>、<STUN_UDP_PORT> 替换为实际值(参考 §1)
ExecStart=/usr/local/derp/bin/derper \
-certmode=manual \
-certdir=/usr/local/derp/certs \
-hostname=<VPS_IP> \
-a :<DERP_TCP_PORT> \
-stun-port=<STUN_UDP_PORT> \
-http-port=-1 \
--verify-clients
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
参数要点:
-certmode=manual:手动证书模式-http-port=-1:关闭 HTTP 端口--verify-clients:开启客户端验证Restart=on-failure+RestartSec=5:崩溃后自动重启
启动并验证:
systemctl daemon-reload
systemctl enable derper
systemctl start derper
systemctl status derper
4.7.2 OpenRC(Alpine)
cat > /etc/init.d/derper << 'EOF'
#!/sbin/openrc-run
description="Tailscale DERP Server"
command="/usr/local/derp/bin/derper"
# 下方 <VPS_IP>、<DERP_TCP_PORT>、<STUN_UDP_PORT> 替换为实际值(参考 §1)
command_args="-certmode=manual -certdir=/usr/local/derp/certs -hostname=<VPS_IP> -a :<DERP_TCP_PORT> -stun-port=<STUN_UDP_PORT> -http-port=-1 --verify-clients"
command_user="root:root"
supervisor=supervise-daemon
respawn_delay=5
respawn_max=0
depend() {
need net
after firewall
}
EOF
参数要点:
-certmode=manual:手动证书模式-http-port=-1:关闭 HTTP 端口--verify-clients:开启客户端验证supervisor=supervise-daemon+respawn_delay=5:崩溃后自动重启(等效 systemd 的Restart=on-failure)
启动并验证:
chmod +x /etc/init.d/derper
rc-update add derper default
rc-service derper start
rc-service derper status
4.8 验证端口监听
| 系统 | 端口检查命令 |
|---|---|
| Debian / Ubuntu / RHEL | ss -tulnp \| grep -E "<DERP_TCP_PORT>\|<STUN_UDP_PORT>" |
| Alpine | netstat -tulnp \| grep -E "<DERP_TCP_PORT>\|<STUN_UDP_PORT>" |
通用验证:
# 本地 TCP 连通性(替换为 DERP 端口)
nc -zv 127.0.0.1 <DERP_TCP_PORT>
# 查看进程
ps aux | grep derper
预期输出:
tcp 0 0 :::<DERP_TCP_PORT> :::* LISTEN 1234/derper
udp 0 0 :::<STUN_UDP_PORT> :::* 1234/derper
如果缺少某一行,说明对应端口未监听成功,需检查服务日志。
查看日志:
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu / RHEL | journalctl -u derper --no-pager -n 30 |
| Alpine | dmesg \| tail -20 |
4.9 异机交叉编译(低内存 VPS)
VPS 内存不足 2GB 编译会 OOM,可在其他机器编译后上传。
# 1) 准备 Go 环境(版本建议 >= 1.21)
go version
# 2) 大陆地区切换下载源
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
# 3) 设定目标平台(示例:Linux AMD64)
export GOOS=linux
export GOARCH=amd64 # ARM64 改为 arm64
export CGO_ENABLED=0
# 4) 构建 derper
go install tailscale.com/cmd/derper@latest
ls ~/go/bin/derper
# 5) 在 VPS 上创建目录(替换 <VPS_IP> 为服务器公网 IP)
ssh root@<VPS_IP> "mkdir -p /usr/local/derp/bin /usr/local/derp/certs"
# 6) 上传到 VPS
scp ~/go/bin/derper root@<VPS_IP>:/usr/local/derp/bin/
# 7) 在 VPS 上验证
ssh root@<VPS_IP>
chmod +x /usr/local/derp/bin/derper
ldd /usr/local/derp/bin/derper # 应输出 "not a dynamic executable"
/usr/local/derp/bin/derper --version
编译参数说明:
CGO_ENABLED=0:生成纯静态二进制,降低运行环境依赖GOOS/GOARCH:目标操作系统和架构
💡 提示:上传并验证通过后,回到上方「§4.6 生成自签名证书」步骤继续完成证书、服务配置与 Tailscale 安装。
5. 安装 Tailscale 客户端
Debian / Ubuntu / RHEL 使用官方一键脚本:
curl -fsSL https://tailscale.com/install.sh | sh
systemctl enable --now tailscaled
tailscale up
Alpine 通过 apk 安装(不支持官方一键脚本):
确保 /etc/apk/repositories 包含 community 仓库(以 Alpine 3.19 为例):
http://dl-cdn.alpinelinux.org/alpine/v3.19/main
http://dl-cdn.alpinelinux.org/alpine/v3.19/community
若缺失可追加:
echo "http://dl-cdn.alpinelinux.org/alpine/v3.19/community" >> /etc/apk/repositories
安装并启动:
apk update
apk add tailscale
rc-update add tailscale default
rc-service tailscale start
tailscale up
完成终端中显示的认证链接登录后,执行 tailscale status 确认状态。
6. 配置 ACL(derpMap)
进入 Tailscale 管理后台 Access controls 的 JSON 编辑器,把下列 derpMap 合并到现有 ACL(不要覆盖其他配置项)。
将以下 JSON 中的
<REGION_ID>、<REGION_CODE>、<VPS_IP>、<DERP_TCP_PORT>、<STUN_UDP_PORT>替换为你的实际值(参考 §1)。
{
"derpMap": {
"OmitDefaultRegions": false, // 保留官方 DERP 作为兜底
"Regions": {
"<REGION_ID>": {
"RegionID": <REGION_ID>, // 自定义区域 ID,建议 900 及以上
"RegionCode": "<REGION_CODE>", // 自定义区域代码
"RegionName": "Custom DERP",
"Nodes": [
{
"Name": "myderper",
"RegionID": <REGION_ID>,
"HostName": "<VPS_IP>", // 必须与证书和 -hostname 一致
"DERPPort": <DERP_TCP_PORT>, // 必须与服务监听端口一致
"STUNPort": <STUN_UDP_PORT>, // 必须与 STUN 监听端口一致
"CanPort80": false,
"InsecureForTests": true // IP + 自签证书场景必须开启
}
]
}
}
}
}
ℹ️ 说明:Tailscale ACL 编辑器支持 HuJSON 格式,
//注释可直接保留,无需删除。
⚠️ 注意:常见坑——
- JSON 尾逗号导致保存失败
- ACL 端口与服务监听端口不一致
HostName与证书 SAN 不一致
7. 客户端重连与配置下发
ACL 保存后,建议客户端重连一次,确保拉取新配置:
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu / RHEL | systemctl restart tailscaled |
| Alpine | rc-service tailscale restart |
| 通用方式 | tailscale down && tailscale up |
建议等待 1-2 分钟后再跑连通性测试。
7.1 启用 Peer Relay(可选)
ℹ️ 说明:Peer Relay 目前处于 Beta 阶段,需要 Tailscale 1.86+。它允许 tailnet 内的设备充当高吞吐中继,直连失败时优先走 Peer Relay,再回退到 DERP。适用于严格 NAT 环境下的大文件传输、高清流媒体等场景。
第一步:在中继设备上开启 Peer Relay
# 确认版本 >= 1.86
tailscale version
# 启用 Peer Relay,指定 UDP 端口
tailscale set --relay-server-port=40000
⚠️ 注意:确保防火墙和云安全组放行该 UDP 端口(如
40000/udp),否则其他设备无法通过 Peer Relay 连接。
第二步:在 ACL 中添加 grant 策略
仅开启端口不够,还必须在 Tailscale 管理后台的 Access controls 中添加 Peer Relay 的 grants 策略。
先查询 DERP 服务器的 Tailscale IP:
tailscale status
输出中第一列 100.x.x.x 即为 Tailscale IP。
在现有 ACL 的 grants 数组中追加 Peer Relay 条目(grants 支持多条共存)。以下是包含基础网络访问和 Peer Relay 的完整示例,将 <RELAY_HOSTNAME> 替换为 DERP 服务器的 Tailscale IP:
{
"grants": [
{
"src": ["*"],
"dst": ["*"],
"ip": ["*"] // 基础网络访问,允许所有设备互通
},
{
"src": ["*"],
"dst": ["<RELAY_HOSTNAME>"], // 替换为 DERP 服务器的 Tailscale IP
"app": {
"tailscale.com/cap/relay": [] // relay 能力,无需额外参数
}
}
],
"acls": [
{
"action": "accept",
"src": ["*"],
"dst": ["*:*"] // 允许所有流量通过
}
]
}
⚠️ 注意:Tailscale ACL 默认拒绝所有流量。如果你的 ACL 中没有
acls规则或网络访问 grant(第一条"ip": ["*"]),设备之间将无法通信,Peer Relay 也不会生效。上方示例中两者都保留以确保正常工作。如果你已有自己的
acls和grants配置,只需将第二条 Peer Relay grant 追加到现有grants数组末尾即可。
dst:必须替换<RELAY_HOSTNAME>为 DERP 服务器的 Tailscale IPtailscale.com/cap/relay:必须的 relay 能力声明
💡 提示:多台 Peer Relay 场景可改用标签精细控制,详见 Tailscale Peer Relays 文档。
第三步:验证
# 生成流量后查看状态
tailscale status | grep peer-relay
# 或用 ping 测试
tailscale ping <对端设备>
当连接走 Peer Relay 时,tailscale status 会显示 peer-relay 而非 direct 或 relay。
禁用 Peer Relay
tailscale set --relay-server-port=""
7.2 启用 Exit Node(可选)
Linux 必须先开启 IP 转发才能作为 Exit Node:
# 如果系统存在 /etc/sysctl.d/ 目录(推荐)
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
# 否则使用 /etc/sysctl.conf
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
⚠️ 注意:如果使用 firewalld,需额外允许 masquerade:
firewall-cmd --permanent --add-masquerade开启 IP 转发后,请确认防火墙默认拒绝转发流量(
ufw、firewalld默认如此),避免意外路由不相关流量。
广播 Exit Node 并启用路由接受:
sudo tailscale up --accept-routes --advertise-exit-node
最后到 Tailscale 管理后台批准 Exit Node:
- 打开 Machines 页面,找到该设备
- 点击设备右侧
...菜单 → Edit route settings - 启用 Use as exit node
💡 提示:如果该设备的用户已在 ACL
autoApprovers中配置了 Exit Node 权限,则会自动批准,无需手动操作。
7.3 网络性能优化(可选)
启用 UDP GRO forwarding 和关闭 GRO list 可提升 Tailscale 的网络吞吐:
# 启用 UDP GRO forwarding
ethtool -K eth0 rx-udp-gro-forwarding on
# 启用 UDP segmentation offload
ethtool -K eth0 rx-gro-list off
# 检查设置
ethtool -k eth0 | grep gro
💡 提示:如果提示
ethtool: command not found:
系统 安装命令 Alpine apk add ethtoolDebian / Ubuntu apt install -y ethtoolRHEL / CentOS / Rocky dnf install -y ethtool
8. 测试与验收
8.1 快速测试命令
# 网络能力检查(UDP / DERP)
tailscale netcheck
# 设备与对等节点状态
tailscale status
# 结构化状态(便于排障与留档)
tailscale status --json
8.2 tailscale netcheck 输出说明
UDP: true:UDP 通信正常Nearest DERP:应接近你设置的自定义区域DERP latency:自建节点延迟越低越好
8.3 tailscale status 输出说明
- 本机是否
active - 对等节点是否可见
- 连接路径是否出现
relay "<REGION_CODE>"或direct ...
8.4 示例输出
ℹ️ 说明:不同版本输出可能略有差异,重点看判读思路。
示例 1:tailscale netcheck
Report:
* UDP: true
* IPv4: yes, 203.0.113.24:41641
* IPv6: no, but OS has support
* MappingVariesByDestIP: false
* HairPinning: false
* Nearest DERP: myderp
* DERP latency:
- myderp: 18.2ms
- tok: 62.4ms
其中:
UDP: true:STUN 打洞能力正常Nearest DERP: myderp:客户端已命中自定义区域MappingVariesByDestIP: false:通常表示 NAT 映射更稳定
示例 2:tailscale status
100.64.0.2 vps-derp linux active; direct 198.51.100.10:41641, tx 12 rx 20
100.64.0.8 laptop windows active; relay "myderp", tx 3 rx 6
其中:
active; direct ...:当前直连active; relay "myderp":当前走 DERP 中继,区域为myderp- 如果长期全部
relay,继续排查 NAT/防火墙/端口策略