问题引入

Tailscale DERP 服务器设计为直接对外提供服务,甚至内置了 Let’s Encrypt 自动证书申请功能。但这样必须直接将 80 和 443 端口分配给 DERP 容器,无法在该服务器上部署其他网站了。

在本文中,我们将在一个容器上部署 Caddy 服务,反向代理到 DERP 容器,从而实现多个网站共存。

DERP 配置

我们使用 Docker Compose 部署 DERP 服务:

compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
services:
derper:
image: ghcr.io/kaaanata/derper:latest
container_name: derper
restart: unless-stopped
environment:
- DERP_DOMAIN=derp.example.com
- DERP_ADDR=:80 # 关键:默认为 443,需要改为非 443 端口
networks:
- shared_bridge
ports:
- "3478:3478/udp"
volumes:
- derp_certs:/app/certs
- derp_data:/app/data

networks:
shared_bridge:
external: true

volumes:
derp_certs:
derp_data:

Caddy 配置

Caddy 配置细节取决于 Caddy 实例的网络环境,本文我们将 Caddy 容器和 DERP 容器放在同一个自定义桥接网络 shared_bridge 中。

创建 shared_bridge 网络:

1
docker network create shared_bridge

Caddy 的 Docker Compose 配置如下:

compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 简单示例
services:
caddy:
cap_add:
- NET_ADMIN
extra_hosts:
- "host.docker.internal:host-gateway"
image: caddy:latest
networks:
- shared_bridge
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
restart: unless-stopped
volumes:
- ./data/conf:/etc/caddy
- ./data/srv:/srv
- caddy_data:/data
- caddy_config:/config

networks:
shared_bridge:
external: true

volumes:
caddy_data:
caddy_config:

Caddy 配置文件 Caddyfile 如下:

./data/conf/Caddyfile
1
2
3
derp.example.com {
reverse_proxy derper # 使用容器名称作为主机名,如果上面用的不是 80 端口,需要加上端口号
}

启动上述各容器,访问 https://derp.example.com,看到以下 DERP 页面即说明部署成功:

DERP 网页截图

(DERP 还需要使用 UDP 3478 端口提供 STUN 服务,别忘了在防火墙打开该端口)

参考资料