Lazy loaded image
🛰️用 Docker 部署 Tailscale DERP,并用 NPM 反代 + 伪装(端口安全策略)
字数 1716阅读时长 5 分钟
2026-6-24
2026-6-23
摘要:本文记录一套“可长期稳定使用”的自建 Tailscale DERP(含 STUN)部署方式:使用 Docker 部署 derper,中继服务通过 Nginx Proxy Manager(NPM)做 HTTPS 入口与证书管理,同时用首页伪装降低暴露特征。重点补全 /derp 反向代理的正确写法,并明确端口暴露策略:UDP 50001 需要对外开放用于 STUN;TCP 33443 只绑定 127.0.0.1 作为 NPM 上游,避免 DERP 后端直接暴露到公网。

〇、部署目标与网络拓扑(先讲清楚)

我们要实现三个目标:
  1. DERP 可用:客户端在无法 P2P 打洞时,能稳定走 DERP 中转。
  1. STUN 可用:客户端能做 UDP 探测与打洞(对网络质量影响很大)。
  1. 入口伪装 + 降低暴露面:域名首页返回正常网页;DERP 后端端口不直接暴露公网,只允许本机反代访问。
推荐结构:
  • derper(Docker):提供 DERP(HTTPS) + STUN(UDP)
  • Nginx Proxy Manager(NPM):负责 derp.example.com:443 的 HTTPS、证书、反向代理与伪装
  • 端口策略
    • UDP 50001:对公网开放(STUN)
    • TCP 33443:仅本机 127.0.0.1 可访问(DERP 后端),外网不可直连
整体拓扑:443 由 NPM 对外提供并反代到本机 33443;STUN 走 UDP 50001 直通
整体拓扑:443 由 NPM 对外提供并反代到本机 33443;STUN 走 UDP 50001 直通

一、前置准备(域名 / 证书 / 防火墙)

1)域名解析

  • 准备域名:derp.0o0.ren
  • DNS A 记录指向服务器公网 IP

2)证书准备

证书可以由 1Panel 或 NPM 签发/管理。本文采用手动挂载证书文件到 derper 容器(适配 DERP_CERT_MODE=manual)。
示例证书路径(按你的实际路径调整):
  • /opt/1panel/ssl/fullchain.pem
  • /opt/1panel/ssl/privkey.pem

3)防火墙放行(关键)

  • 必须放行UDP 50001(STUN 对外端口)
  • 建议不放行TCP 33443(DERP 后端端口,本文会绑定 127.0.0.1,外网天然访问不到)
DERP 端口暴露策略速记卡
DERP 端口暴露策略速记卡
注意:如果你服务器有面板(1Panel/宝塔等),通常有“云安全组 + 面板防火墙 + 系统防火墙”三层,任何一层没放行 UDP 都可能导致 netcheck 显示 UDP 不可用。

二、Docker Compose 部署 derper(推荐安全端口暴露策略)

进入你的部署目录(示例):
docker-compose.yml(按你的场景整理后的推荐版本):
启动:

三、NPM 反代 DERP + 伪装首页(补全正确 /derp 配置)

1)在 NPM 创建 Proxy Host(建议)

  • Domain Names:derp.0o0.ren
  • Scheme:https
  • Forward Hostname / IP:127.0.0.1
  • Forward Port:33443
  • SSL:启用证书(NPM 自动申请或导入)
因为我们把 derper 后端绑定到了 127.0.0.1:33443,所以 NPM 上游用 127.0.0.1:33443 是最稳妥且“外网不可见”的做法。

2)高级配置(关键:/derp 必须 proxy_pass + WebSocket)

将下面内容加入 NPM 的 Advanced(高级配置)。这份是“可直接用”的完整模板:

常见坑说明(务必写清)

  • 如果你的后端 derper 实际是 HTTP(不是 HTTPS),就要把 proxy_pass 改为 http://127.0.0.1:33443/derp;,并删除/注释
    • proxy_ssl_server_name on;
    • proxy_ssl_name $host;
  • /derp 是长连接场景,timeout 建议拉长,否则容易莫名断线。
  • 伪装首页只负责“看起来像网站”,DERP 真正服务入口是 /derp

3)world.html(伪装页面示例)

你的伪装首页其实就是 NPM 容器(或你挂载的数据目录)里的一段静态 HTML。上面 location = /root /data/html; 代表 NPM 里这个目录,try_files /world.html 就会读取同目录下的 world.html
你当前使用的 world.html(原样)如下:
备注:这段代码里有 eval(...) 与混淆内容,属于“伪装页面效果”用途;仅建议放在你专用的 DERP 域名上,不要复用到其他业务域名。

四、Tailscale 控制台登记 derpMap(示例)

在控制台 ACL 配置里添加自建 DERP 节点(示例模板):
说明:
  • DERPPort 写 443(因为外部是 NPM 的 443)
  • STUNPort 写你对公网开放的 UDP 端口(本文为 50001)

五、验证与排错(确保真的可用)

1)验证伪装是否生效

  • 打开:https://derp.0o0.ren/
    • 应返回 world.html 内容
  • https://derp.0o0.ren/derp 不一定有“网页”,但至少不应 502/504

2)客户端侧验证(强烈建议)

在任意一台已加入 tailnet 的机器执行:
期望看到:
  • UDP 可用(否则 P2P/体验会明显变差)
  • 能识别/探测到你的自建 DERP 区域(或在相关输出里出现自建节点)
进一步可用性确认:
  • 如果显示 via DERP(...) 说明当前在走中继(可接受但延迟高)
  • 如果显示对方公网/NAT 地址且不出现 DERP 字样,说明 P2P 打洞成功(最佳)

六、总结(一句话落地)

用 Docker 部署 derper,并通过 NPM 反代 /derp(WebSocket 必开)+ 首页伪装,同时采用“UDP 50001 对公网开放、TCP 33443 仅本机监听”的端口策略,可以在保证可用性的同时显著降低 DERP 后端暴露风险,适合长期稳定跑在生产环境。
上一篇
OpenWrt 下 OpenClash 完美配合 Cloudflare Tunnel 直连配置指南
下一篇
OpenWrt 上让 Tailscale + OpenClash 完美共存:在外也能享受家里分流