Certbot 证书自动化教程 / 第 10 章:多域名与通配符证书
第 10 章:多域名与通配符证书
10.1 证书类型概述
在实际运维中,一个域名对应一张证书往往不是最优方案。理解不同证书类型的适用场景,能有效降低管理复杂度。
证书覆盖范围对比
| 证书类型 | 覆盖范围 | 示例 | 验证方式 |
|---|---|---|---|
| 单域名证书 | 一个域名 | example.com | HTTP-01 / DNS-01 |
| SAN 证书 | 多个独立域名 | example.com, blog.com | HTTP-01 / DNS-01 |
| 通配符证书 | 所有同级子域名 | *.example.com | 仅 DNS-01 |
| SAN + 通配符 | 根域名 + 通配符 | example.com, *.example.com | 仅 DNS-01 |
SAN(Subject Alternative Name)简介
SAN 是 X.509 证书中的扩展字段,允许一张证书包含多个域名标识(DNS 名称)。Let’s Encrypt 签发的所有证书都是 SAN 证书,单个证书最多支持 100 个域名标识。
# 查看证书中的 SAN 信息
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text | grep "DNS:"
# 输出示例:
# DNS:example.com, DNS:www.example.com, DNS:api.example.com
10.2 多域名证书(SAN 证书)
申请多域名证书
# 方式一:单个 -d 参数列出所有域名
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d api.example.com \
-d admin.example.com
# 方式二:合并为一个 -d 参数(逗号分隔)
sudo certbot certonly --nginx \
-d example.com,www.example.com,api.example.com,admin.example.com
# 使用 webroot 模式
sudo certbot certonly --webroot -w /var/www/certbot \
-d example.com -d www.example.com -d api.example.com
# 使用 DNS 验证
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d example.com -d www.example.com -d api.example.com
跨域名 SAN 证书
# 一张证书覆盖多个完全不同的域名
sudo certbot certonly --webroot -w /var/www/certbot \
-d site1.com \
-d site2.com \
-d site3.org
注意: 所有域名必须都能通过相同的验证方式完成域名验证。使用 webroot 模式时,所有域名需要指向同一个 Web 根目录。
不同 Webroot 的多域名
# 每个域名使用不同的 webroot 路径
sudo certbot certonly \
--webroot -w /var/www/site1 -d site1.com \
--webroot -w /var/www/site2 -d site2.com
10.3 通配符证书
通配符证书覆盖范围
| 证书域名 | 匹配 | 不匹配 |
|---|---|---|
*.example.com | www.example.com | example.com |
api.example.com | sub.www.example.com | |
mail.example.com | example.org | |
anything.example.com |
申请通配符证书
# 必须使用 DNS-01 验证
# Cloudflare 插件
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d example.com \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
# Route53 插件
sudo certbot certonly \
--dns-route53 \
-d example.com \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
# 手动 DNS 验证
sudo certbot certonly --manual \
--preferred-challenges dns \
-d example.com \
-d "*.example.com"
通配符 + 根域名
# 推荐:同时包含根域名和通配符
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d example.com \
-d "*.example.com"
生成的证书同时适用于 example.com 和所有 *.example.com 子域名。
多级通配符不支持
# ❌ 以下写法无效
-d "*.sub.example.com" # 仅匹配 sub.example.com 的下一级
-d "*.*.example.com" # 不支持多个通配符层级
# ✅ 需要多个通配符证书
-d "*.example.com" # 匹配 xxx.example.com
-d "*.sub.example.com" # 匹配 xxx.sub.example.com
10.4 多站点管理策略
策略一:每个站点一张证书
site1.com → 证书 1 (site1.com)
site2.com → 证书 2 (site2.com)
site3.com → 证书 3 (site3.com)
sudo certbot certonly --nginx -d site1.com
sudo certbot certonly --nginx -d site2.com
sudo certbot certonly --nginx -d site3.com
优点: 隔离性好,续期互不影响 缺点: 证书数量多,管理开销大
策略二:合并为多域名证书
site1.com + site2.com + site3.com → 一张 SAN 证书
sudo certbot certonly --nginx \
-d site1.com -d site2.com -d site3.com
优点: 减少证书数量 缺点: 所有站点共用一张证书,续期时全部受影响
策略三:通配符 + 根域名
example.com + *.example.com → 一张通配符证书
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d example.com -d "*.example.com"
优点: 一张证书覆盖所有子域名 缺点: 仅限同级子域名,需要 DNS 验证
策略四:混合方案
example.com + *.example.com → 通配符证书 1
blog.com + www.blog.com → 证书 2
api.partner.com → 证书 3
策略选择指南
| 场景 | 推荐策略 | 理由 |
|---|---|---|
| 单个独立站点 | 每站一证 | 简单清晰 |
| 同一主域下多个子域 | 通配符证书 | 管理简单 |
| 多个不同域名 | SAN 证书 | 减少证书数量 |
| 多个不同域+子域 | 混合方案 | 灵活高效 |
| 微服务架构 | 通配符 + SAN | 覆盖全面 |
10.5 向现有证书添加域名
# 使用 --expand 参数向现有证书添加域名
sudo certbot --nginx --cert-name example.com \
-d example.com \
-d www.example.com \
-d api.example.com
–expand 与 –expand 关键区别
| 参数 | 行为 |
|---|---|
| 无 –expand | 如果证书名已存在,会报错 |
--expand | 向现有证书添加新域名,替换旧证书 |
实际操作
# 查看当前证书
sudo certbot certificates
# 原证书包含: example.com, www.example.com
# 添加 api.example.com
sudo certbot --nginx --cert-name example.com \
-d example.com \
-d www.example.com \
-d api.example.com
# 验证
sudo certbot certificates
# 现在包含: example.com, www.example.com, api.example.com
10.6 证书管理命令
列出所有证书
sudo certbot certificates
输出示例:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: example.com
Serial Number: abcdef123456
Key Type: ECDSA
Domains: example.com www.example.com api.example.com
Expiry Date: 2025-08-10 12:00:00+00:00 (VALID: 80 days)
Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
Certificate Name: blog.example.com
Serial Number: 7890abcdef12
Key Type: ECDSA
Domains: blog.example.com
Expiry Date: 2025-07-15 06:00:00+00:00 (VALID: 55 days)
Certificate Path: /etc/letsencrypt/live/blog.example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/blog.example.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
证书重命名
# 重命名证书
sudo certbot certrename --cert-name old-name --new-name new-name
删除证书
# 删除证书
sudo certbot delete --cert-name example.com
# 交互式删除
sudo certbot delete
撤销证书
# 撤销证书(向 CA 发送撤销请求)
sudo certbot revoke --cert-name example.com
# 撤销并删除
sudo certbot revoke --cert-name example.com --delete-after-revoke
# 撤销原因
sudo certbot revoke --cert-name example.com --reason keyCompromise
10.7 多域名 Nginx 配置
通配符证书 Nginx 配置
# 通用 SSL 参数
# /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
# 主站
# /etc/nginx/sites-available/example.com.conf
server {
listen 80;
server_name example.com *.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
root /var/www/example.com;
}
# 子站 - 使用同一个通配符证书
# /etc/nginx/sites-available/app.example.com.conf
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 另一个子站
# /etc/nginx/sites-available/blog.example.com.conf
server {
listen 80;
server_name blog.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name blog.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/snippets/ssl-params.conf;
root /var/www/blog;
}
10.8 证书合并与拆分
合并多个单域证书为 SAN 证书
# 原来有三个独立证书
sudo certbot certificates
# example.com
# blog.example.com
# api.example.com
# 删除旧证书(确保 Nginx 不再引用)
sudo certbot delete --cert-name blog.example.com
sudo certbot delete --cert-name api.example.com
# 申请新的 SAN 证书
sudo certbot certonly --nginx \
-d example.com \
-d blog.example.com \
-d api.example.com
# 更新 Nginx 配置中的证书路径
拆分 SAN 证书为独立证书
# 原来有一张 SAN 证书包含多个域名
sudo certbot delete --cert-name example.com
# 分别申请独立证书
sudo certbot certonly --nginx -d example.com
sudo certbot certonly --nginx -d blog.example.com
sudo certbot certonly --nginx -d api.example.com
10.9 证书信息查看
使用 OpenSSL
# 查看证书详情
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text
# 查看证书域名
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text | grep "DNS:"
# 查看有效期
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates
# 查看颁发者
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -issuer
# 查看序列号
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -serial
使用 Certbot
# 列出所有证书
sudo certbot certificates
# 查看特定证书
sudo certbot certificates --cert-name example.com
检查在线证书状态
# 使用 curl 检查远程服务器的证书
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates -subject
# 使用 ssl-checker 脚本
curl -s "https://www.ssllabs.com/ssltest/analyze.html?d=example.com&latest"
10.10 最佳实践
- 同类站点使用通配符: 同一主域下的子站点优先使用通配符证书
- 独立站点使用 SAN: 将功能相关的独立域名合并到一个 SAN 证书
- 不要超过 50 个域名: 单个证书过多域名会增加管理复杂度
- 合理命名证书: 使用主域名作为证书名(
--cert-name) - 记录域名清单: 维护每个证书包含的域名列表,便于管理
- 分开续期风险: 核心业务站点使用独立证书,避免 SAN 证书续期影响所有站点