打造零维护的私有工业级 Tailscale DERP 中继服务器(Nginx Stream SNI 分流 + 泛域名证书)

打造零维护的私有工业级 Tailscale DERP 中继服务器(Nginx Stream SNI 分流 + 泛域名证书)

在自建 VPN 或组网工具(如 Tailscale)时,官方公共 DERP 中继服务器有时会因为地理位置或网络运营商策略导致延迟较高、丢包严重。为此,我们可以利用一台位于优质线路(如 CN2 GIA)上的 VPS 搭建专属的私有 DERP 中继服务器。

然而,生产环境的 VPS 通常已经部署了 Nginx 并且占用了标准的 443 端口来托管各种 Web 应用。如何在不冲突、不影响现有业务的前提下,让私有 DERP 服务器完美共存并实现端口复用?本文将分享一套基于 Nginx Stream 模块的 SNI 端口多路复用与复用 acme.sh 泛域名证书的"工业级"完美部署方案。


一、 方案设计与优势

  1. 端口多路复用(SNI Routing):利用 Nginx 的 stream 模块在第四层(L4)读取 TLS 握手时的 SNI(Server Name Indication)信息。将访问 derper.example.com 的流量精准转发至内部的 derper 监听端口,而其余所有常规 HTTPS 网站流量则正常转发至 Web 后端,实现 443 端口完美共存。Nginx stream 是纯 TCP 四层透传,不改源地址、不终止 TLS,因此不违反 DERP 对直连公网的要求(云厂商七层负载均衡那种不行,四层透传没问题)。
  2. 零维护证书同步:直接通过软链接(Symlink)复用系统已有的 acme.sh 泛域名证书(如 *.example.com)。证书由 acme.sh 自动续期,derper 无需占用 80 端口进行独立的 HTTP 验证,做到了真正的"一次配置,永久省心"。

二、 准备工作


三、 完整部署步骤

第一步:安装与配置 derper

  1. 使用 Go 语言官方命令直接安装 Tailscale 的 derper 工具:

    go install tailscale.com/cmd/derper@latest
    sudo cp ~/go/bin/derper /usr/local/bin/
    
  2. 创建专用的证书存放目录:

    sudo mkdir -p /etc/derper-certs
    
  3. 使用软链接将 acme.sh 生成的泛域名证书关联到 derper 目录中(请将路径替换为您实际的 acme.sh 证书路径):

    sudo ln -sf /path/to/.acme.sh/example.com_ecc/fullchain.cer /etc/derper-certs/derper.example.com.crt
    sudo ln -sf /path/to/.acme.sh/example.com_ecc/example.com.key /etc/derper-certs/derper.example.com.key
    

第二步:配置 Systemd 后台托管服务

为了确保 derper 能够开机自启并异常崩溃后自动拉起,我们需要为其编写一个 systemd 服务文件。

执行以下命令创建服务配置:

sudo bash -c 'cat << "EOF" > /etc/systemd/system/derper.service
[Unit]
Description=Tailscale Private DERP Server
After=network.target

[Service]
User=root
ExecStart=/usr/local/bin/derper --hostname=derper.example.com --http-port=-1 -a=:33443 --certdir=/etc/derper-certs
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF'

重载并启动服务:

sudo systemctl daemon-reload
sudo systemctl enable --now derper

第三步:配置 Nginx Stream SNI 分流

修改 Nginx 的主配置文件(通常位于 /etc/nginx/nginx.conf),在全局层级(与 http { ... } 块同级)添加 stream 模块,实现根据域名进行四层流量分发:

stream {
    # 根据客户端请求的 SNI 域名进行分流映射
    map $ssl_preread_servername $backend_name {
        derper.example.com derper_backend;
        default            web_backend;
    }

    # DERP 中继后端(本地 33443 端口)
    upstream derper_backend {
        server 127.0.0.1:33443;
    }

    # 常规 Web 网站后端(例如内部 8443 端口或其他服务)
    upstream web_backend {
        server 127.0.0.1:8443;
    }

    server {
        listen 443 reuseport;
        listen [::]:443 reuseport;
        proxy_pass $backend_name;
        ssl_preread on;
    }
}

测试 Nginx 配置并平滑重载:

sudo nginx -t
sudo systemctl reload nginx

第四步:在 Tailscale 控制台中挂载私有节点

登录 Tailscale 管理后台,进入 Access Controls(访问控制),在 ACL 规则的 JSON 中加入自定义的 derpMap 区域配置:

{
    "derpMap": {
        "OmitDefaultRegions": false,
        "Regions": {
            "901": {
                "RegionID": 901,
                "RegionCode": "Custom-Region",
                "RegionName": "My Private DERP",
                "Nodes": [
                    {
                        "Name": "901a",
                        "RegionID": 901,
                        "HostName": "derper.example.com"
                    }
                ]
            }
        }
    }
}

注:derpMap 之外的字段(如你已有的 grants / acls 授权规则)请保留自己的配置,无需改动。RegionID 使用 900 系列是 Tailscale 官方示例的做法,避开与官方区域的数字段冲突即可。

保存后,在客户端机器上执行网络检查命令:

tailscale netcheck

如果在输出列表中成功看到了刚才配置的私有区域,说明你的私有 DERP 中继服务器已经正式上线并被客户端识别了!


四、 常见排错与日常维护

  1. 日志提示 no config path specified; using .../derper.key: 这是 derper 源码中的标准硬编码提示信息,表示没有通过 -c 传入额外的 JSON 配置文件。只要命令行参数中正确指定了 --certdir 和 --hostname,此提示可直接忽略。
  2. 证书自动续期后的更新: 由于我们采用了软链接直接指向 acme.sh 的证书目录,当 acme.sh 定期自动更新证书后,文件内容会自动生效。你只需要在续期脚本的钩子中,或者手动执行一次服务重启即可加载最新证书:
    sudo systemctl restart derper
    
  3. netcheck 里看不到私有节点: 客户端本地策略未及时同步,重跑 tailscale up 或重启 Tailscale 客户端,强制拉取控制台最新配置即可。
  4. 节点显示但延迟异常/不可用: 检查服务器防火墙是否放行了 UDP 3478 端口。DERP 服务器需要开放 HTTP(80)、HTTPS(443)、STUN(3478) 三个端口,其中 3478 是 STUN 端口,常用于客户端测速与直连探测,只放行 443 会导致节点"注册成功但体验不佳"。

五、 总结

通过这套架构,我们不仅拥有了一个完全自主可控、高带宽低延迟的私有 Tailscale 中继网络,还极其优雅地解决了 443 端口被 Web 服务占用的痛点,并借助 acme.sh 做到了证书管理的"零维护"。如果你也有多服务共存和异地组网的需求,不妨也动手试试吧!

← 返回文章列表