Nginx反向代理DERP全流程实操:从零搭建专属高速节点,告别自建网络卡顿

为什么你需要折腾 Nginx 反向代理 DERP?

💡 推荐阅读:从被挂马到彻底躺平:Linux服务器安全攻防实战记录与加固指南

玩过 TailscaleHeadscale 的朋友,对 DERP(Detoured Encrypted Relay Protocol)肯定不陌生。简单说,DERP 就是当两台设备无法直接打洞(NAT 穿透失败)时,负责中转流量的中继服务器。

很多新手在自建 Headscale 服务后,发现外网设备访问内网资源时,速度慢得让人抓狂。排查到最后,问题往往出在默认的 DERP 服务器上——要么是官方的公共 DERP 节点距离你太远,要么是网络高峰期拥堵严重。

这时候,自建一个专属 DERP 服务器就成了刚需。但很多教程只教你部署 DERP 服务本身,却忽略了最关键的一步:如何用 Nginx 反向代理它。要知道,直接裸奔的 DERP 服务不仅容易被扫描攻击,而且如果你手头只有一台 80/443 端口的服务器,不靠反向代理根本没法玩。

今天,笔者就带你从零开始,手把手搞定 Nginx 反向代理 DERP 的全流程。全程实操,照着敲命令就行。

环境准备:开工前的三件套

💡 延伸阅读:还在手动改端口?Nginx反向代理配置实战:从入门到高可用,三种方案横评对比

在开始敲键盘之前,请确认你手头已经准备好了以下东西,缺一不可:

  • 一台具有公网 IP 的云服务器(建议选离你物理位置近的机房,比如你在国内就选国内大厂,海外就选就近区域的 VPS)。这里多说一句,靠谱的云服务商很重要,别贪便宜买那种线路超售严重的小厂机器,否则 DERP 建好了速度也上不去。
  • 一个已经解析到该服务器 IP 的域名(例如 derp.example.com),并且确保该域名的 80 和 443 端口没有被防火墙拦截。
  • 服务器上已经装好了 Docker 和 Docker Compose。如果你还没装,可以用下面的一键脚本快速搞定:
# 安装 Docker
curl -fsSL https://get.docker.com | bash -s docker

# 启动 Docker 并设置开机自启
systemctl enable --now docker

# 验证安装
docker --version

实操步骤:Nginx 反向代理 DERP 全流程

💡 深度技术指南:Linux服务器刚上线就被黑?这份安全加固实操指南请收好

这里笔者推荐使用 Docker Compose 来部署,这样不仅环境隔离干净,而且升级维护都极其方便。整个流程分为三步:配置 DERP 服务 -> 配置 Nginx 反向代理 -> 生成证书并验证

第一步:编写 DERP 服务端配置

DERP 服务本身并不复杂,它需要一个配置文件来定义端口、密钥等。我们先创建一个项目目录,并写入配置文件。

# 创建项目目录
mkdir -p /opt/derp && cd /opt/derp

# 创建 derp 配置文件
cat <<'EOF' > derp.yaml
# DERP 服务监听端口
DerpPort: 9443
# 自动生成或手动指定的私钥路径
PrivateKeyPath: /app/keys/derp_server_private_key
# 公钥路径(会自动生成)
PublicKeyPath: /app/keys/derp_server_public_key
# 开启 HTTP 验证(可选,用于客户端健康检查)
VerifyClientURL: ""
EOF

这里有一个细节要注意:DERP 默认监听的是 9443 端口,但我们之后会用 Nginx 将 443 端口的流量反代到它。所以,在配置里我们不需要让 DERP 直接绑定 443。

第二步:用 Docker Compose 编排 Nginx + DERP

接下来是最核心的部分。我们会在同一个 Compose 文件里定义两个服务:derp-servernginx。这样 Nginx 可以通过 Docker 内部网络直接访问 DERP 服务,无需暴露额外的宿主机端口。

# 创建 docker-compose.yml
cat <<'EOF' > docker-compose.yml
version: '3.8'

services:
  derp-server:
    image: ghcr.io/willscott/derper:latest
    container_name: derp-server
    restart: always
    volumes:
      - ./keys:/app/keys
      - ./derp.yaml:/app/derp.yaml
    command: ["--config=/app/derp.yaml"]
    networks:
      - derp-net
    # 注意:这里我们不映射 9443 端口到宿主机,只暴露给内部 Nginx 使用

  nginx:
    image: nginx:alpine
    container_name: derp-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - derp-server
    networks:
      - derp-net

networks:
  derp-net:
    driver: bridge
EOF

在上面的编排中,nginx 容器将宿主机的 80/443 端口映射进来,并通过 Docker 内部网络名 derp-server 来转发请求。这样,外部用户访问你的域名 443 端口,实际上就是 Nginx 在处理 TLS 终结,然后转发给内部的 DERP 服务。

第三步:编写 Nginx 反向代理配置

这是整个教程的灵魂所在。Nginx 配置需要做两件事:一是处理 WebSocket 升级(DERP 协议基于 WebSocket),二是把流量反代到内部 DERP 容器。

# 创建 nginx.conf
cat <<'EOF' > nginx.conf
events {}

http {
    # 开启 gzip 压缩,减少中继数据体积
    gzip on;
    gzip_types text/plain application/json application/octet-stream;

    # 限制上传大小,DERP 中继大文件时有用
    client_max_body_size 100M;

    upstream derp_backend {
        server derp-server:9443;
        keepalive 32;
    }

    server {
        listen 80;
        server_name derp.example.com;
        # 强制跳转 HTTPS
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name derp.example.com;

        # SSL 证书配置(使用 certbot 或手动放置的证书)
        ssl_certificate /etc/nginx/certs/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        # 关键配置:WebSocket 代理
        location / {
            proxy_pass https://derp_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # 禁用缓冲,保证实时性
            proxy_buffering off;
            proxy_cache off;

            # 超时时间设置长一点,防止长连接断开
            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
        }
    }
}
EOF

注意看,proxy_pass 指向的是 https://derp_backend。因为 DERP 服务内部自己也是 TLS 加密的(默认端口 9443),所以 Nginx 需要以 HTTPS 方式去访问它。如果你在 DERP 容器里关闭了 TLS(--http-port=9443 且不启用 TLS),那么这里就要改成 http://。不过为了安全,建议保留 TLS。

第四步:获取 SSL 证书并启动服务

有了 Nginx 配置,我们还需要合法的 SSL 证书。最简单的方式是用 certbot 签发,但因为我们还没启动服务,所以先手动放一个自签名或者提前申请好的证书。

这里推荐使用 acme.sh 或者 certbot 的 DNS 验证方式提前申请。假设你已经把证书文件放到了 /opt/derp/certs/ 目录下:

# 创建证书目录
mkdir -p /opt/derp/certs

# 将你的 fullchain.pem 和 privkey.pem 上传到该目录
# 例如使用 scp 命令

# 启动所有服务
cd /opt/derp
docker compose up -d

# 查看日志,确认 DERP 和 Nginx 都正常运行
docker compose logs -f

看到 derp-server 输出类似 DERP server listening on :9443 的日志,并且 Nginx 没有报错,就说明部署成功了。

避坑清单:这五个坑我替你踩过了

在部署过程中,笔者遇到过不少问题,这里挑几个最典型的分享给大家,能帮你省下不少排查时间。

坑点 现象 解决方案
证书链不完整 Tailscale 客户端始终无法连接,提示 TLS 握手失败 确保 fullchain.pem 包含中间证书,不要只放叶子证书
WebSocket 握手失败 DERP 日志显示 404 或 400 错误 检查 Nginx 配置中 UpgradeConnection 头是否设置正确
防火墙未放行端口 外部访问超时,但服务器本地 curl 正常 在云服务商安全组和系统防火墙中放行 80/443 端口
DERP 容器内部 TLS 与 Nginx 冲突 Nginx 报 502 Bad Gateway 确认 proxy_pass 的协议(http/https)与 DERP 容器实际监听协议一致
域名解析到旧 IP 客户端连接被重置 检查 DNS 解析记录,确保 A 记录指向当前服务器 IP

如何验证你的 DERP 节点已生效?

服务部署好之后,别急着高兴,我们还需要做一步验证。在你的 Headscale 控制端 的配置文件中,添加你自建的 DERP 节点信息,然后重启 Headscale 服务。

# 在 Headscale 的 config.yaml 中添加以下内容
derp:
  urls:
    - https://control.example.com/derp-map
  paths:
    - /etc/headscale/derp.yaml

然后在 /etc/headscale/derp.yaml 中定义你的自定义节点:

regions:
  900:
    regionid: 900
    regioncode: "myderp"
    regionname: "My Home DERP"
    nodes:
      - name: "home1"
        regionid: 900
        hostname: "derp.example.com"
        ipv4: "你的服务器IP"
        stunport: 3478
        stunonly: false
        derpport: 443

最后,在客户端执行 tailscale netcheck 命令,如果看到你自定义的 Region 延迟很低,且没有报错,那就说明 Nginx 反向代理 DERP 已经大功告成了!

写在最后的几句心里话

自建 DERP 节点确实能大幅提升 Tailscale/Headscale 组网的中继速度,尤其是当你有跨地域传输大文件的需求时,效果立竿见影。但笔者也要提醒一句:服务器的带宽和线路质量决定了中继速度的上限。如果你用的是那种 1M 小水管,再怎么优化 Nginx 也无济于事。

所以,如果你真的想把自建网络体验拉满,建议还是选择口碑好、带宽充足、线路优化的云服务商。域名方面也尽量选择正规注册商,避免后续备案或解析出幺蛾子。毕竟,折腾这些技术是为了让生活更便捷,而不是为了给自己添堵。

好了,今天的实操分享就到这里。如果你在部署过程中遇到了什么奇怪的报错,欢迎在评论区留言,我们一起探讨。下次见!

相关技术专题与延伸阅读

滚动至顶部