为什么需要自动化证书管理#
传统的 SSL/TLS 证书需要付费购买、手动配置、定期续期。随着 HTTPS 普及,手动管理证书的方式变得不可持续:
- 手动续期容易遗忘:证书过期导致服务中断
- 成本问题:商业证书每年费用不菲
- 管理复杂:多台服务器、多域名管理难度大
- 安全风险:过期的证书或配置错误影响安全
ACME 协议(Automatic Certificate Management Environment)正是为解决这些问题而设计的。
什么是 ACME 协议#
ACME 是由 IETF 制定的标准协议(RFC 8555),用于自动化证书的颁发、更新和撤销。Let’s Encrypt 是最著名的 ACME 服务提供商,提供免费、自动化的 SSL/TLS 证书。
ACME 工作流程#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
┌─────────────┐ ┌─────────────────┐
│ 客户端 │◄───────►│ ACME 服务器 │
│ (Certbot) │ │ (Let's Encrypt) │
└─────────────┘ └─────────────────┘
│ │
│ 1. 注册账户 │
│──────────────────────►│
│◄──────────────────────│
│ │
│ 2. 发起证书请求 │
│──────────────────────►│
│ │
│ 3. 挑战验证 │
│ (HTTP-01/DNS-01) │
│◄──────────────────────│
│ │
│ 4. 颁发证书 │
│◄──────────────────────│
|
ACME 挑战类型#
ACME 服务器需要验证你对域名的控制权,有三种挑战方式:
HTTP-01 挑战#
最常用的验证方式,通过 HTTP 请求验证:
1
2
3
4
5
6
7
8
|
# Certbot 自动处理流程
# 1. 在服务器创建验证文件
.well-known/acme-challenge/XYZ123
# 2. Let's Encrypt 访问
# http://example.com/.well-known/acme-challenge/XYZ123
# 3. 验证成功后颁发证书
|
要求:
- 端口 80 可访问
- 能创建 HTTP 文件
- 不支持 wildcard(通配符)证书
DNS-01 挑战#
通过 DNS TXT 记录验证,适合:
- 无法开放 HTTP 端口
- 需要 wildcard(通配符)证书
- 内网环境
1
2
3
4
5
6
|
# Certbot DNS 验证
certbot certonly --manual --preferred-challenges dns \
-d *.example.com -d example.com
# 需要添加 DNS TXT 记录
_acme-challenge.example.com. 300 IN TXT "XYZ123abc..."
|
TLS-ALPN-01 挑战#
通过 TLS 握手验证,不需要 HTTP 端口,适合特殊场景。
Certbot 安装与使用#
安装 Certbot#
1
2
3
4
5
6
7
8
9
|
# Debian/Ubuntu
apt-get update
apt-get install certbot python3-certbot-nginx
# CentOS/RHEL
yum install certbot python3-certbot-nginx
# Docker 方式
docker pull certbot/certbot
|
基本用法#
1
2
3
4
5
6
7
8
|
# 为 Nginx 自动配置证书
certbot --nginx -d example.com -d www.example.com
# 仅获取证书,不修改 Nginx 配置
certbot certonly --webroot -w /var/www/html -d example.com
# 交互式申请证书
certbot certonly
|
申请证书示例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 使用 webroot 方式
certbot certonly \
--webroot \
-w /var/www/html \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos \
--no-eff-email
# 使用 standalone 方式(需要停止现有服务)
certbot certonly \
--standalone \
-d example.com \
--preferred-challenges http-01
|
获取证书后的文件#
1
2
3
4
5
|
/etc/letsencrypt/live/example.com/
├── fullchain.pem # 完整证书链
├── privkey.pem # 私钥
├── cert.pem # 服务器证书
└── chain.pem # 中间证书链
|
查看证书信息#
1
2
3
4
5
6
7
8
|
# 查看证书详情
certbot certificates
# 详细证书信息
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text
# 检查证书有效期
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates
|
自动续期配置#
Let’s Encrypt 证书有效期为 90 天,Certbot 安装后会自动配置 cron 任务。
检查自动续期#
1
2
3
4
5
|
# 查看续期定时任务
systemctl list-timers | grep certbot
# 或查看 cron 配置
cat /etc/cron.d/certbot
|
续期任务通常每天运行两次,只有证书剩余 30 天时才会实际续期。
手动测试续期#
1
2
3
4
5
|
# 测试续期(不实际执行)
certbot renew --dry-run
# 手动执行续期
certbot renew
|
Nginx 自动部署#
在续期后自动重载 Nginx:
1
2
3
4
5
6
7
|
# 创建部署脚本
cat > /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
|
完整续期配置示例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 创建续期脚本
cat > /usr/local/bin/cert-renew.sh << 'EOF'
#!/bin/bash
# 续期所有证书
certbot renew --quiet --post-hook "systemctl reload nginx"
# 日志记录
logger "Certificate renewal completed"
EOF
chmod +x /usr/local/bin/cert-renew.sh
# 添加到 crontab(每天凌晨 3 点执行)
crontab -e
# 添加以下行:
# 0 3 * * * /usr/local/bin/cert-renew.sh >> /var/log/cert-renew.log 2>&1
|
Wildcard 证书申请#
Wildcard(通配符)证书可以保护所有子域名:
1
2
3
4
5
6
7
8
9
10
11
12
|
# 申请 Wildcard 证书(需要 DNS 验证)
certbot certonly \
--manual \
--preferred-challenges dns \
-d *.example.com \
-d example.com \
--email admin@example.com \
--agree-tos
# 需要添加以下 DNS TXT 记录:
# 名称: _acme-challenge.example.com
# 值: XYZ123456789...
|
使用 DNS API 自动验证#
使用 DNS 提供商的 API 自动完成 DNS 验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# Cloudflare 示例
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d *.example.com \
-d example.com
# 创建凭证文件
cat > /etc/letsencrypt/cloudflare.ini << 'EOF'
dns_cloudflare_api_key = your_cloudflare_api_key
dns_cloudflare_email = your_email@example.com
EOF
chmod 600 /etc/letsencrypt/cloudflare.ini
|
支持的 DNS 提供商:
- Cloudflare
- AWS Route 53
- Google Cloud DNS
-阿里云 DNS
- 腾讯云 DNSPod
多域名证书管理#
SAN 证书(多域名单证书)#
1
2
3
4
5
6
|
# 一个证书保护多个域名
certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d blog.example.com \
-d api.example.com
|
分别管理不同域名#
1
2
3
4
5
6
|
# 为不同域名创建不同配置
certbot certonly --nginx -d example.com -d www.example.com
certbot certonly --nginx -d other.com -d www.other.com
# 查看所有证书
certbot certificates
|
常见问题与解决方案#
端口占用#
1
2
3
4
|
# 停止 Nginx 后再申请
systemctl stop nginx
certbot certonly --standalone -d example.com
systemctl start nginx
|
挑战失败#
1
2
3
4
5
|
# 检查 .well-known 目录权限
chmod -R 755 /var/www/html/.well-known
# 确认文件可访问
curl http://example.com/.well-known/acme-challenge/test
|
证书链问题#
1
2
3
4
5
6
7
|
# 修复证书链
certbot certonly --reinstall -d example.com
# 或手动合并证书链
cat /etc/letsencrypt/live/example.com/cert.pem \
/etc/letsencrypt/live/example.com/chain.pem \
> /etc/letsencrypt/live/example.com/fullchain.pem
|
续期失败#
1
2
3
4
5
|
# 查看详细错误日志
tail -f /var/log/letsencrypt/letsencrypt.log
# 手动强制续期
certbot renew --force-renewal
|
安全最佳实践#
1. 定期测试续期#
1
2
|
# 每周测试一次
certbot renew --dry-run
|
2. 监控证书过期#
1
2
3
4
5
6
|
# 检查证书剩余天数
certbot certificates | grep -A2 "example.com"
# 或使用 openssl
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem \
-noout -enddate
|
3. 备份证书#
1
2
3
|
# 备份证书目录
tar -czf letsencrypt-backup-$(date +%Y%m%d).tar.gz \
/etc/letsencrypt/
|
4. 限制私钥权限#
1
2
3
|
# 设置严格的权限
chmod 600 /etc/letsencrypt/live/example.com/privkey.pem
chmod 700 /etc/letsencrypt/live/example.com/
|
5. 使用安全配置#
1
2
3
4
5
|
# Nginx 配置示例
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
|
ACME 协议和 Let’s Encrypt 彻底改变了 SSL/TLS 证书的管理方式:
| 特性 |
传统方式 |
ACME 自动化 |
| 成本 |
付费(每年数百到数千) |
免费 |
| 有效期 |
1-2 年 |
90 天 |
| 续期 |
手动 |
自动 |
| 管理 |
分散 |
集中 |
| 部署 |
手动配置 |
自动部署 |
通过本文的配置方法,可以实现证书的自动化申请、部署和续期,再也不用担心证书过期问题。
参考来源#