本文记录一次在 Linux 主机上从源码部署 Tailscale 自定义 DERP Server 的完整过程。部署使用 vfox 管理 Go,并交由用户级 systemd 管理。

最终监听端口如下:

服务协议默认监听端口手动修改后端口
http-port证书挑战或跳转80-1(关闭)
DERPHTTPS/TCP4438443
STUNUDP34783478

本文显式关闭 derper 的辅助 HTTP 监听,只保留 HTTPS 8443 和 STUN 3478。自定义 HTTPS 端口通过 DERP Map 的 DERPPort 声明。

1. 部署环境与重要限制

部署前确认以下条件:

  • 已安装golang环境,本文使用 vfox+Golang 插件。
  • TCP 8443、UDP 3478 当前没有被其他服务占用。

端口占用可以先检查:

ss -ltnup | rg ':(3478|8443)\b'

开始之前,需要了解自定义 DERP 的几个限制:

  1. DERP 服务本身必须使用 HTTPS,客户端通过 HTTP Upgrade 建立双向通道。
  2. 本配置需要放行 HTTPS 8443、STUN 3478 和 ICMP。
  3. 当前服务未启用客户端校验。任何知道公网 IP 和 Map 参数的人都可以把它加入自己的 tailnet,存在带宽滥用和流量费用风险。

详细要求参见 Tailscale Custom DERP Servers 官方文档。

本文主机位于 NAT 后方,因此采用端口转发。这是官方不支持的实验性拓扑:本机验证正常不代表公网 DERP 可用,在完成公网 HTTPS、STUN 和真实中继测试前,不应视为生产部署完成。

2.安装 Golang 环境

Golang 环境自行参考官网教程

可使用Vfox工具进行安装和版本控制

vfox install golang
vfox use golang

3. 编译 derper

官方文档通常建议安装最新版:

go install tailscale.com/cmd/derper@latest

检查版本和编译器:

/opt/derp-servers/bin/derper --version
go version -m /opt/derp-servers/bin/derper

验证编译产物:

derper --version: 1.102.2-ERR-BuildInfo
module: tailscale.com v1.102.2
Go: go1.26.5
SHA-256: bed842649072fa85d08840aaf8ad6662689993bc46d4c4fb4f0fa89733cd008c

-ERR-BuildInfo 是使用 go install 构建时该命令自身显示的版本后缀;准确的模块版本以 go version -m 输出为准。

4. 创建 derper-user 用户并安装到目录

创建用户

  useradd \
    --system \
    --user-group \
    --create-home \
    --home-dir /home/derper-user \
    --shell /usr/sbin/nologin \
    --comment "Tailscale DERP service account" \
    derper-user

创建程序、状态和用户 unit 目录:

install -d -o derper-user -g derper-user -m 0755 \
  /home/derper-user/.local/bin \
  /home/derper-user/.local/share/derper \
  /home/derper-user/.config/systemd/user

三个目录的用途:
/home/palworld/.local/bin
存放 derper 可执行文件。

/home/palworld/.local/share/derper
存放 DERP 节点私钥、TLS 证书及 DERP Map。

/home/palworld/.config/systemd/user
存放 palworld 的 systemd 用户服务配置。

安装二进制:

install -o derper-user -g derper-user -m 0755 \
  /opt/derp-servers/bin/derper \
  /home/derper-user/.local/bin/derper

安装域名证书(可选)

如果80 443端口可使用,可让程序自动申请证书。

手动安装证书方法:derper 的 manual 模式按 <hostname>.crt 和 <hostname>.key 查找文件,因此安装时需要给证书改名,并严格限制私钥权限:

  chown derper-user:derper-user \
    /home/derper-user/.local/share/derper/example.com.crt \
    /home/derper-user/.local/share/derper/example.com.key

  chmod 0644 /home/derper-user/.local/share/derper/example.com.crt
  chmod 0600 /home/derper-user/.local/share/derper/example.com.key

5. 创建 systemd 用户服务

创建 /home/derper-user/.config/systemd/user/derper.service:

[Unit]
Description=Tailscale custom DERP server
Documentation=https://tailscale.com/docs/reference/derp-servers/custom-derp-servers
After=default.target

[Service]
Type=simple
ExecStart=/home/derper-user/.local/bin/derper -c /home/derper-user/.local/share/derper/derper.key -a :8443 -http-port -1 -stun-port 3478 -certmode manual -hostname example.com -certdir /home/derper-user/.local/share/derper
Restart=on-failure
RestartSec=5s


[Install]
WantedBy=default.target

自动申请证书配置,需要授予绑定 80/443 的权限,只需要开通端口就可以自动完成证书申请

如果使用普通用户的 systemd --user 运行 需要 授予二进制低端口权限

sudo setcap cap_net_bind_service=+ep /home/derper-user/.local/bin/derper

  ExecStart=/home/palworld/.local/bin/derper \
    -c /home/palworld/.local/share/derper/derper.key \
    -a :443 \
    -http-port 80 \
    -stun-port 3478 \
    -certmode letsencrypt \
    -hostname cuu.blackbullet.cn \
    -certdir /home/palworld/.local/share/derper/certs \
    -acme-email your-email@example.com

主要参数说明:

参数作用
-c 持久化 DERP 节点私钥;非 root 运行时该参数必填
-a :8443在 TCP 8443 提供 DERP HTTPS 服务
-http-port -1完全关闭辅助 HTTP 监听
-stun-port 3478STUN 服务监听 UDP 3478
-certmode manual使用手动安装的本地证书链和私钥
-hostname example.comTLS 证书和 DERP Map 使用的服务器域名
-certdir ...保存 TLS 证书和私钥

由于服务只监听高端口,用户 unit 不需要 root 权限或额外 capability。DERP Map 中的 DERPPort 必须与 -a 保持一致,否则客户端仍会尝试连接默认 HTTPS 443。

6. 启用用户服务与开机自启

确保 derper-user 即使没有登录会话,用户级 systemd 也能在开机后持续运行:

loginctl enable-linger derper-user

/run/user/<UID> 必须由 systemd-logind 创建,不能用 mkdir 手工替代。下面通过 id -u derper-user 动态取得 UID,避免假定所有主机上 derper-user 都是 UID 1001。

重新加载并启动服务:

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user daemon-reload

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user enable --now derper.service

如果已经登录到 derper-user 的 Shell,可以直接使用:

systemctl --user enable --now derper.service

首次启动时,derper 会自动生成并持久化 DERP 节点身份私钥:

/home/derper-user/.local/share/derper/derper.key

TLS 文件则是前一步安装的:

/home/derper-user/.local/share/derper/example.com.crt
/home/derper-user/.local/share/derper/example.com.key

derper.key 和 TLS 私钥用途不同,但都必须持久化并限制访问权限。

7. 可选步骤-配置 DERP Map (给 Tailscale用的)

将以下内容合并到 Tailscale tailnet policy:

自定义 Region ID 应使用 Tailscale 预留的 900~999 范围。随后进入 Tailscale 管理后台的 Access controls/policy 编辑器,合并并保存配置,等待控制平面把新 Map 下发到客户端。

{
  "derpMap": {
    "Regions": {
      "900": {
        "RegionID": 900,
        "RegionCode": "custom-derp",
        "RegionName": "Custom DERP",
        "Nodes": [
          {
            "Name": "custom",
            "RegionID": 900,
            "HostName": "example.com",
            "IPv4": "27.151.72.226",
            "IPv6": "none",
            "DERPPort": 8443
          }
        ]
      }
    }
  }
}

9. 验证部署

检查服务状态

systemctl --user --no-pager --full status derper.service

应看到:

Active: active (running)

检查监听端口

ss -ltnup | rg ':(3478|8443)\b'

应能看到:

  • TCP 8443 由 derper 以 TLS/HTTPS 监听。
  • UDP 3478 由 derper 监听。

10. 日常运维

查看实时日志:

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  journalctl --user -u derper.service -f

重启服务:

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user restart derper.service

停止服务:

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user stop derper.service

确认开机自启和运行状态:

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user is-enabled derper.service

runuser -u derper-user -- \
  env XDG_RUNTIME_DIR=/run/user/"$(id -u derper-user)" \
  systemctl --user is-active derper.service

loginctl show-user derper-user -p Linger

预期分别为 enabled、active 和 Linger=yes。

参考资料