基于docker的caddy反向代理方案
Posted on Tue 04 March 2025 in howto
用户自行搭建的多个网络服务(self-hosted services),在使用它们时,如果不配置相应的DNS服务,则需要直接输入IP地址和端口号进行访问,非常不便。而且,如果其中还有使用了自签名证书的服务,用浏览器访问时还需要设置例外情况,很不优雅。因此,用caddy为家庭网络服务提供反向代理服务,既可以提供基于域名的访问方式,其自动申请和更新 let's encrypt 证书的功能又可以免除在浏览器中设置例外的麻烦,算是比较好的解决方案。
具体的设置方式如下:
- docker-compose.yaml:
services:
caddy:
build:
context: .
dockerfile: Dockerfile
container_name: caddy
restart: unless-stopped
env_file:
- .env
environment:
- CLOUDFLARE_EMAIL=${CF_EMAIL}
- CLOUDFLARE_API_TOKEN=${CF_API_TOKEN}
- ACME_AGREE=true
ports:
- 80:80
- 443:443
volumes:
- caddy-config:/config
- caddy-data:/data
- ./Caddyfile:/etc/caddy/Caddyfile
networks:
- caddynet # add other containers onto this network to use dns name
volumes:
caddy-config:
caddy-data:
# create this first before running the docker-compose - docker network create caddy
networks:
caddynet:
external: true
由于我们希望给自建服务分配已注册域名之下的子域名(sub-domain),而且方便起见想为其颁发通配符证书,根据 let's encrypt 的要求,必须采用 DNS-01 challenge,为此,我们需要将域名服务商提供的 API token 以及账号对应的 email 地址写入 .env 文件。caddy 官方的 docker image 中不包含适配域名服务商进行 DNS-1 认证的模块,所以我们需要根据实际情况自行编译并加入对应的模块。
- Dockerfile
FROM caddy:builder AS builder
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
假定域名服务商是 cloudflare,因此 Dockerfile 中加入了 cloudflare 相关模块。这个页面有适用于其他服务商的模块,可根据你的实际情况选用并对 Dockerfile 和 docker-compose.yaml 、.env 文件作相应的修改。
- Caddyfile
*.homelab.your_domain.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
propagation_delay 2m
resolvers 1.1.1.1
}
@trueNAS host truenas.homelab.your_domain.com
handle @trueNAS {
reverse_proxy 192.168.6.2:80
}
@adguardhome host adguard.homelab.your_domain.com
handle @adguardhome {
reverse_proxy adguardhome:8001
}
@portainer host portainer.homelab.your_domain.com
handle @portainer {
reverse_proxy https://portainer:9443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}
}
上面的示例中,假设子域名是 *.homelab.your_domain.com,tls 一节作用是向 let's encrypt 申请这些子域名的通配符 ssl 证书。然后,caddy 反向代理了运行在 192.168.6.2:80 的 truenas 服务、运行在名为 adguardhome 的 docker 容器中的 AdGuardHome 服务,以及一个运行在名为 portainer 的 docker 容器中的 portainer 服务。由于 portainer 提供的是 https 端口,为了避免证书的混淆,其设置中需加入 transport http 一节以忽略其自签名证书。
同时还需要注意的是,在配置 adguardhome 和 portainer 的 docker 环境时,container_name 需要与 caddyfile 中引用的一致,并且需要将它们都加入 caddy 所在的 caddynet 网络,即:
services:
container_name: adguardhome
networks:
- caddynet
networks:
caddynet:
external: true
将上面提到的4个文件放在同一目录下。运行命令:
docker network create caddynet
docker compose up -d
祝好运。