DERP(Designated Encrypted Relay for Packets)是 Tailscale 的中继与连通性组件。它主要承担两件事:

  1. 协助节点打洞,尽量建立直连
  2. 直连失败时,作为中继节点转发流量

两种部署方式:

  • 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.xxx1347713478


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 也不会生效。上方示例中两者都保留以确保正常工作。

如果你已有自己的 aclsgrants 配置,只需将第二条 Peer Relay grant 追加到现有 grants 数组末尾即可。

  • dst必须替换 <RELAY_HOSTNAME> 为 DERP 服务器的 Tailscale IP
  • tailscale.com/cap/relay:必须的 relay 能力声明

💡 提示:多台 Peer Relay 场景可改用标签精细控制,详见 Tailscale Peer Relays 文档

第三步:验证

# 生成流量后查看状态
tailscale status | grep peer-relay

# 或用 ping 测试
tailscale ping <对端设备>

当连接走 Peer Relay 时,tailscale status 会显示 peer-relay 而非 directrelay

禁用 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 转发后,请确认防火墙默认拒绝转发流量(ufwfirewalld 默认如此),避免意外路由不相关流量。

广播 Exit Node 并启用路由接受:

sudo tailscale up --accept-routes --advertise-exit-node

最后到 Tailscale 管理后台批准 Exit Node:

  1. 打开 Machines 页面,找到该设备
  2. 点击设备右侧 ... 菜单 → Edit route settings
  3. 启用 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 ethtool
Debian / Ubuntu apt install -y ethtool
RHEL / 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/防火墙/端口策略