上一篇文章介绍了 Caddy 单域名 HTTPS 部署方式, 通过 Caddyfile 实现静态资源托管、反向代理以及自动 HTTPS。
当项目进一步拆分为多个独立服务时,通常会为不同服务配置独立子域名。
随着项目规模增加,通常会拆分出更多服务,例如:
- API 服务;
- 管理后台;
- 博客系统;
- 文件服务;
- 监控平台等。
这些服务通常会使用不同的子域名:
api.example.comadmin.example.comblog.example.comcdn.example.com如果每个子域名单独申请 HTTPS 证书,需要维护多个证书配置。
此时可以使用泛域名证书(Wildcard Certificate):
*.example.com通过一个证书覆盖多个一级子域名,实现统一 HTTPS 管理。
什么是泛域名证书?
泛域名证书,也称通配符证书(Wildcard Certificate)。
它通过*匹配指定层级下的所有子域名。
例如:
*.example.com可以匹配如:
api.example.comblog.example.comadmin.example.com但不支持:
test.api.example.com如果需要支持多级子域名,则需要申请:
*.api.example.com泛域名与单域名区别
| 类型 | 单域名证书 | 泛域名证书 |
|---|---|---|
| 示例 | example.com | *.example.com |
| 覆盖范围 | 单个域名 | 一级子域名 |
| 验证方式 | HTTP Challenge | DNS Challenge |
| 配置难度 | 简单 | 较高 |
| 适用场景 | 单站点 | 多服务、多子域名 |
| 自动续签 | 支持 | 支持 |
为什么泛域名需要 DNS Challenge?
普通 HTTPS 证书通常使用 HTTP Challenge。
验证流程为:
申请证书↓CA 返回验证信息↓服务器提供验证文件↓CA 访问验证地址↓签发证书例如:
example.com/.well-known/acme-challenge/但是泛域名:
*.example.com无法通过 HTTP Challenge 验证。
因为 CA 需要确认:
申请者是否拥有整个域名的 DNS 控制权限。
因此泛域名证书需要使用DNS Challenge。
验证流程:
申请证书↓插件调用 DNS Provider API↓自动创建 TXT 记录_acme-challenge.example.com↓CA 查询 TXT 记录↓验证成功↓签发证书准备环境
本文示例:
域名:example.com
目标:*.example.com
DNS 服务商:阿里云 DNS
Web Server:Caddy需要准备:
- 一个自己的域名;
- DNS 服务商 API 权限;
- 支持 DNS Provider 的 Caddy。
如果服务器位于中国大陆:
- 域名需要提前完成备案,详见域名备案。
- 网站服务需要符合相关管理要求
安装支持 DNS Challenge 的 Caddy
Caddy 默认支持自动 HTTPS。
但是:DNS Challenge需要额外安装对应的 DNS Provider 插件。
例如,阿里云 DNS:
github.com/caddy-dns/alidnsCloudflare:
github.com/caddy-dns/cloudflare本文以 Docker 部署方式为例。
使用 Docker 构建支持 DNS Provider 的 Caddy。
由于官方 Caddy 镜像默认不包含 DNS Provider,需要基于官方镜像重新构建。
目录结构为:
caddy/├── Dockerfile├── Caddyfile├── docker-compose.yaml├── .env├── data/└── config/- 使用
vim编辑Dockerfile文件。
vim Dockerfile内容:
FROM caddy:builder AS builder
ENV GOPROXY=https://goproxy.cn,direct
RUN xcaddy build \ --with github.com/caddy-dns/alidns
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy国内服务器构建时可能无法访问 Go 官方代理,因此这里使用国内 Go Proxy 提高依赖下载成功率。
- 构建
docker build -t caddy-custom .构建完成后,当前镜像已经包含:
dns.providers.alidns插件。
- 使用
vim编辑.env文件
以阿里云为例,将 AccessKey ID 和 AccessKey Secret 写入到文件中。
ALIYUN_ACCESS_KEY_ID=你的AccessKeyIDALIYUN_ACCESS_KEY_SECRET=你的AccessKeySecret- 使用
vim编辑docker-compose.yaml文件
services: caddy: image: caddy-custom:latest container_name: caddy restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: # Caddy 配置文件 - ./Caddyfile:/etc/caddy/Caddyfile:ro # 自动申请的证书、ACME 数据等 - ./data:/data # Caddy 配置持久化 - ./config:/config environment: ALIYUN_ACCESS_KEY_ID: ${ALIYUN_ACCESS_KEY_ID} ALIYUN_ACCESS_KEY_SECRET: ${ALIYUN_ACCESS_KEY_SECRET}如果 Caddy 与后端服务运行在不同 Docker Compose 网络中:
推荐创建共享 Docker Network:
docker network create proxy然后让 Caddy 和后端服务加入同一个网络。
如果后端服务运行在宿主机,也可以使用:
network_mode: host直接访问宿主机端口。
services: caddy: image: caddy-custom:latest container_name: caddy restart: unless-stopped network_mode: host volumes: # Caddy 配置文件 - ./Caddyfile:/etc/caddy/Caddyfile:ro # 自动申请的证书、ACME 数据等 - ./data:/data # Caddy 配置持久化 - ./config:/config environment: ALIYUN_ACCESS_KEY_ID: ${ALIYUN_ACCESS_KEY_ID} ALIYUN_ACCESS_KEY_SECRET: ${ALIYUN_ACCESS_KEY_SECRET}docker compose 会自动读取当前目录下的
.env文件。
host 模式适合:
- Caddy 在宿主机
- 后端服务也在宿主机
- 需要监听宿主网络
- 编辑
Caddyfile
example.com, *.example.com {
tls { dns alidns { access_key_id {env.ALIYUN_ACCESS_KEY_ID} access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET} } }
handle { root * /data/home file_server }}- 启动容器
docker compose up -d- 验证证书申请情况
docker compose logs -f caddy成功时会看到类似:
obtaining certificatepresenting DNS challengecertificate obtained successfully等内容。
验证:
openssl s_client \-connect api.example.com:443 \-servername api.example.com泛域名证书下的多服务配置
泛域名证书的主要用途,就是让多个子域名共享同一个 HTTPS 证书。
例如:
*.example.com可以同时覆盖:
api.example.comadmin.example.comblog.example.comcdn.example.comCaddy 可以通过同一个 Wildcard 证书统一管理这些 HTTPS 请求。
example.com, *.example.com {
tls { dns alidns { access_key_id {env.ALIYUN_ACCESS_KEY_ID} access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET} } }
@api host api.example.com handle @api { reverse_proxy 127.0.0.1:8000 }
@admin host admin.example.com handle @admin { reverse_proxy 127.0.0.1:9000 }
@blog host blog.example.com handle @blog { root * /var/www/blog file_server }
@cdn host cdn.example.com handle @cdn { root * /var/www/cdn file_server }}未匹配的子域名会进入默认 handle。
这样 Caddy 会自动:
- 使用 DNS Challenge 验证域名所有权;
- 申请 Wildcard 证书;
- 自动续签证书;
- 为不同子域名提供 HTTPS。
常见 DNS Provider
| DNS 服务商 | Provider 名称 |
|---|---|
| 阿里云 DNS | alidns |
| 腾讯云 DNSPod | tencentcloud |
| Cloudflare | cloudflare |
| AWS Route53 | route53 |
| 华为云 DNS | huaweicloud |
| Google Cloud DNS | gcpdns |
DNS Provider 插件属于第三方模块,使用前请确认对应仓库维护状态。
更多 Provider 见 Caddy DNS Provider 官方仓库。
常见问题
泛域名证书可以覆盖所有子域名吗?
不可以。
例如:
*.example.com只能匹配一级子域名,如:
api.example.comblog.example.comadmin.example.com但是无法匹配:
*.api.example.com如果需要支持多级子域名,需要申请:
*.api.example.comCaddy 为什么需要重新构建?
因为官方 Caddy 镜像只包含官方模块。
DNS Challenge Provider(例如阿里云 DNS、Cloudflare 等)属于第三方模块,需要通过 xcaddy 编译进去。
构建后 Caddy 才支持:alidns等。
Caddy 可以代理 Docker 容器吗?
可以。
如果 Caddy 与后端服务运行在同一个 Docker Compose 网络中,可以直接使用服务名访问。
DNS 验证失败怎么办?
检查:
- AccessKey 是否正确
- API 是否拥有 DNS 权限
- TXT 记录是否生效
查看:
dig TXT _acme-challenge.example.com总结
泛域名证书适用于:
- 多个 Web 服务
- API 服务拆分
- Docker 多容器部署
- 个人服务器环境
通过:
Caddy+DNS Challenge+Wildcard Certificate可以实现:
- 自动申请证书
- 自动续签
- 多子域名统一 HTTPS
- 降低维护成本
对于个人服务器和中小型项目:
*.example.com是一种更加优雅的 HTTPS 管理方案。
参考资料
本文内容参考以下官方文档和标准资料:
-
Caddy 官方文档:介绍 Caddy 的安装、配置、自动 HTTPS、反向代理以及模块扩展等功能。
-
Caddy Automatic HTTPS:介绍 Caddy 自动 HTTPS、ACME 证书申请以及自动续签机制。
-
xcaddy 官方仓库:用于构建包含第三方模块的自定义 Caddy 二进制文件。
-
Caddy DNS Provider 插件:提供不同 DNS 服务商对应的 DNS Challenge 插件实现。
-
Let’s Encrypt 官方文档:介绍免费 TLS 证书签发流程以及 ACME 协议相关内容。
-
ACME 协议标准(RFC 8555):定义自动化申请、验证和管理 TLS 证书的标准流程。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时





