为什么需要自动化证书管理

传统的 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 天
续期 手动 自动
管理 分散 集中
部署 手动配置 自动部署

通过本文的配置方法,可以实现证书的自动化申请、部署和续期,再也不用担心证书过期问题。


参考来源