
利用 Caddy 反代 Tailscale DERP 服务
文章摘要
猿_AI
需求背景
因为运营商对于 IPv4 及 公网IP 的政策收窄,现在的普通家宽所获得的 IP 都是 NAT 过后的私有 IP。人在外已经无法通过 DDNS 等方式直连到家里的 NAS 等服务了。为了能够从外部访问到家里的 NAS 等设备,需要通过 Tailscale 的 VPN 服务来实现外部访问。
前期准备
- VPS / 云服务器
- 域名
- Docker Compose 文件
- Caddyfile
VPS / 云服务器如果位于国内,那么相关的域名需要进行备案,不然无法访问。我这次使用的是 日本 的 国际版阿里云服务器,2C1G200M 。
网络质量可以参考下方
整体的性能、网络测试可以参考 NodeQuality
Docker 环境安装
1 | apt install curl -y && apt install wget -y |
Docker Compose
完整 Docker Compose 文件如下:
1 | networks: |
Docker Compose 解析
这个 docker-compose.yml 文件定义了两个服务:caddy 和 derper,它们都连接到一个名为 caddynet 的 外部 Docker 网络。
networks 配置
1 | networks: |
PS:需要手动用 docker network create caddynet 创建 caddynet 的网络。
服务:Caddy
1 | services: |
| 项目 | 说明 |
|---|---|
| image | 使用自定义构建的 caddy 镜像(可能包含额外插件)。[^1]见解释。 |
| ports | 仅开放 443(HTTPS),若要自动申请证书,建议开启 80(被注释掉)。 |
| volumes | 绑定本地配置: - Caddyfile 是主配置文件- caddy_data 存储证书等数据- caddy_config 存储配置状态 |
| environment | 使用环境变量 CLOUDFLARE_API_TOKEN,供 Caddy 使用 DNS 方式申请证书(Cloudflare 提供 DNS 验证)。 |
| networks | 使用共享网络 caddynet,以便跟其他服务(如 derper)互通。 |
服务:Derper
1 | derper: |
| 项目 | 说明 |
|---|---|
| image | 使用 fredliang/derper 镜像,运行 Tailscale 的中继服务器。 如果需要启用 Client verification,见[^2] |
| DERP_DOMAIN | 设置公开使用的域名(需与 Caddy 配置反向代理对应)。 |
| DERP_ADDR=:8080 | 监听容器内部的 8080 端口(不直接对外开放,走反向代理)。 |
| DERP_STUN=true | 启用 STUN(用于打洞) |
| DERP_STUN_PORT=3478 | STUN 使用的端口,映射到主机 3478/udp |
| ports | 仅暴露 3478/udp,用于 STUN 功能,8080 没有暴露(仅被 Caddy 内部反代)。 |
| networks | 与 caddy 共享 caddynet 网络,Caddy 可以通过容器名访问 derper 服务。 |
访问流程
1 | graph TD |
Caddyfile
1 | derper.example.com { |
解析
- derper.example.com
这是一个 站点块(site block),表示这个配置应用于请求域名为 derper.saru.im 的 HTTPS 请求。
- 所有访问 https://derper.saru.im 的流量都会被这个配置处理。
- 默认监听端口为 443(HTTPS),Caddy 会自动监听。
- reverse_proxy derper:8080
反向代理指令。
- 意思是:将访问 https://derper.saru.im 的流量,转发给名为 derper 的容器的 8080 端口。
- derper 是 Docker Compose 中的服务名,Caddy 和 derper 都在 caddynet 网络中,因此可以通过容器名直接解析。
相当于
1 | [Client] ---> Caddy (443) ---> http://derper:8080 (容器间通信) |
- tls { … }
这一块配置 HTTPS/TLS 的证书获取方式。
1 | tls { |
- 启用自动申请证书(Let’s Encrypt)。
- 使用 Cloudflare DNS 方式验证域名所有权,适用于:
- 无公网 80 端口
- 或在内网中运行服务时
- {env.CLOUDFLARE_API_TOKEN} 表示从环境变量中读取 Cloudflare 的 API Token。
PS:
- 确保 Cloudflare 上有一个 A 记录 derper.saru.im 指向你 Caddy 所在服务器的公网 IP;
- 环境变量 CLOUDFLARE_API_TOKEN 应至少包含 Cloudflare 的 Zone.DNS 权限。API 的申请请自行查阅教程;
- 如果你用了 .env 文件,确保 docker-compose.yml 和 .env 在同一目录下;
.env
1 | CLOUDFLARE_API_TOKEN=type_your_own_api_here |
整体目录结构如下
1 | derper-caddy/ |
[^1]:Caddy 的容器镜像是编译了第三方的插件,如果有需要编译自己的 Caddy,可以自己去编译。可以参考 ^caddy_custom
https://github.com/caddy-dns/cloudflare
https://github.com/caddyserver/forwardproxy
[^2]: Client verification
- 安装 Tailscale 的 Linux 客户端,教程自行查找;
- Docker Compose 文件中的
# DERP_VERIFY_CLIENTS=true去掉#启用。
1 | FROM caddy:builder AS builder |
运行
Caddyfile,Docker Compose File,.ENV 都准备好后在终端执行。
1 | docker compose up -d |
验证
浏览器打开 https://derper.example.com 显示 DERP 字样证明成功。
Tailscale 组网
这部分可以参考 多多先生 的文章。
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自夜間通信




