用 Caddy 自动申请主域名、子域名和自定义域名的 HTTPS 证书
SaaS 支持客户子域名和自定义域名是很常见的需求。Caddy 是一个支持自动申请 HTTPS 证书的 Web server。最近用 Caddy 实现了子域名和自定义域名的自动 HTTPS 配置,记录如下以供参考。
主域名证书
Caddyfile 内容如下:
domain.com {
reverse_proxy localhost:8080
}
DNS 只需要将域名 A 记录指向 IP,Caddy 即可自动申请 Let's Encrypt 的证书。
⚠️ Caddy 的 data 目录存放着申请到的证书,必须将它配置在持久化的储存卷。
子域名证书
为了支持无限多的子域名,子域名需要使用通配符证书。对于通配符证书 Caddy 需要有操作 DNS 记录的权限以完成证书颁发的 DNS 验证。
要操作 DNS,Caddy 需要安装扩展。以 Cloudflare DNS 为例,首先安装 Caddy 的 cloudflare 扩展:
FROM caddy:2.6-builder AS builder
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare
FROM caddy:2.6
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
然后编辑 Caddyfile 配置:
*.sitedomain.com {
reverse_proxy localhost:8080
tls {
dns cloudflare {env.CF_API_TOKEN}
}
}
其中 sitedomain.com 域名 DNS 需要托管在 Cloudflare,并且获取 API Token 放到 Caddyfile 的配置中。
你可以在这里查看所有支持的 DNS:https://github.com/caddy-dns 。
自定义域名
自定义域名由用户设置,不能硬编码到配置文件中。Caddy 通过 On-Demand TLS 这个特性支持自定义域名的 HTTPS 配置。开启 On-Demand TLS 后,每当有一个域名请求到达 Caddy,Caddy 会自动为这个域名申请证书。
但如果对域名不做限制,可能会遇到一些恶意请求消耗证书申请的额度,导致无法申请正常的域名证书。所以 Caddy 提供了一个配置,可以在申请证书之前请求一个 API,获得 HTTP 200 响应才继续申请证书。于是在应用层要实现一个校验域名是否有效的接口,这里假设实现为 localhost:8080/check
,Caddy 会发出一个 check?domain=xxx
的 GET 请求,应用根据自己的逻辑判断是否返回 200 状态。
在 Caddyfile 的顶部添加全局配置:
{
on_demand_tls {
ask http://localhost:8080/check
}
}
在 Caddyfile 底部添加捕获所有域名的配置:
https:// {
reverse_proxy localhost:8080
tls {
on_demand
}
}
这样 Caddy 在遇到一个未签发证书的域名时,会先请求 /check
API 校验域名是否有效,通过之后再申请证书。
配置汇总
以上所有配置汇总如下:
{
on_demand_tls {
ask http://localhost:8080/check
}
}
domain.com {
reverse_proxy localhost:8080
}
*.sitedomain.com {
reverse_proxy localhost:8080
tls {
dns cloudflare {env.CF_API_TOKEN}
}
}
https:// {
reverse_proxy localhost:8080
tls {
on_demand
}
}
现在 Caddy 已经支持自动为主域名、子域名和自定义域名申请 HTTPS 证书。