SSL 证书有效期要缩到 47 天了!用 ACME 协议 + Certbot 在亚马逊云科技 EC2 上实现自动续期全攻略

CA/Browser Forum 去年通过了一个让运维集体头疼的决议:SSL/TLS 证书有效期要分阶段缩短,到 2029 年只剩 47 天。意味着一年要续 8 次以上,手动操作直接不可能了。这篇文章手把手教你在亚马逊云科技 EC2 + Nginx 环境下用 ACME 协议搞定自动续期,顺便对比一下 ACM 托管方案。

先说背景:为什么证书有效期越来越短

CA/Browser Forum 在 2025 年 4 月通过了正式决议,时间表长这样:

时间节点证书有效期上限域名验证复用期
现在398 天398 天
2026 年 3 月 15 日200 天200 天
2027 年 3 月100 天100 天
2029 年 3 月47 天~10 天

47 天是怎么算的:31 天(覆盖大月)+ 15 天缓冲 + 1 天冗余。

缩短有效期的核心目的就三个:

  1. 确保证书信息跟实际情况一致
  2. 缩小证书被盗用或错发的风险窗口
  3. 倒逼全行业搞自动化

说白了,以后不搞自动化就等着半夜被告警叫醒吧。

两条路线:ACM 托管 vs 自建 ACME

路线一:亚马逊云科技 ACM(省心方案)

如果你的架构用了 ALB / CloudFront / API Gateway 这些亚马逊云科技托管服务,直接用 ACM(Amazon Certificate Manager)申请证书就行。ACM 的证书到期自动续期,不需要你操心。零配置、零运维。

适合:前面挂了负载均衡器或 CDN 的架构。

路线二:EC2 自建 Nginx(本文重点)

但现实是,很多团队出于各种原因(历史架构、特殊合规要求、第三方证书),直接在 EC2 上跑 Nginx 并用第三方证书。这种情况下证书管理就是你自己的事。

这篇文章就是为这种场景写的。

环境准备

  • Amazon Linux 2023(AL2、Ubuntu、RHEL 命令类似)
  • Nginx 已安装并运行
  • 域名 DNS A 记录指向 EC2 公网 IP
  • 安全组放行 80(HTTP)和 443(HTTPS)

安装 Nginx

# Amazon Linux 2023
sudo dnf install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx

安装 Certbot

# pip 方式
sudo pip3 install certbot certbot-nginx

# 或 dnf 方式
sudo dnf install certbot python3-certbot-nginx -y

基础 Nginx 配置

编辑 /etc/nginx/conf.d/yourdomain.conf

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

验证:

sudo nginx -t
sudo systemctl reload nginx
curl http://yourdomain.com  # 应该返回你的页面

Certbot 三种模式详解

模式一:Standalone — 简单但有短暂停机

原理:Certbot 在本地 80 端口起一个临时 Web 服务器处理 ACME HTTP-01 验证。因为 Nginx 占着 80 端口,必须先停 Nginx。

# 停 Nginx 释放 80 端口
sudo systemctl stop nginx

# 申请证书
sudo certbot certonly --standalone -d yourdomain.com

# 重启 Nginx
sudo systemctl start nginx

拿到证书后配置 HTTPS:

server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

自动续期带钩子:

sudo certbot renew --dry-run \
  --pre-hook "systemctl stop nginx" \
  --post-hook "systemctl start nginx"

踩坑提醒:每次续期有 10-30 秒停机,Nginx 被停掉了。适合开发测试环境,生产慎用。

模式二:Webroot — 零停机

原理:Certbot 把验证文件放到 Nginx 的 Web 根目录,Nginx 直接提供文件,不需要停服务。

关键一步:在 Nginx 配置里给 ACME 验证路径开个口子,不要被 301 重定向吃掉。

server {
    listen 80;
    server_name yourdomain.com;

    # ACME 验证直接走,不重定向
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }

    # 其他请求重定向 HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

我之前踩过一个坑:忘了加这个 location 块,80 端口全部 301 到 HTTPS,结果 Let’s Encrypt 的验证请求也被重定向了,签发直接失败。排查了半小时才想起来。

验证路径是否可访问:

sudo mkdir -p /usr/share/nginx/html/.well-known/acme-challenge
echo "test" | sudo tee /usr/share/nginx/html/.well-known/acme-challenge/test-token

# 应返回 200,不是 301
curl -I http://yourdomain.com/.well-known/acme-challenge/test-token

sudo rm /usr/share/nginx/html/.well-known/acme-challenge/test-token

申请证书:

sudo certbot certonly --webroot \
  -w /usr/share/nginx/html \
  -d yourdomain.com

续期不需要钩子,Nginx 全程运行:

sudo certbot renew --dry-run

小贴士:加个 deploy 钩子在续期后自动 reload Nginx 加载新证书:

# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx

模式三:Nginx 插件 — 零停机 + 全自动

原理:Certbot 直接跟 Nginx 对话,临时改 Nginx 配置处理验证,完成后自动装证书并 reload,全程不用你管。

# 一条命令搞定
sudo certbot --nginx -d yourdomain.com

这条命令一次完成四件事:

  1. 通过 Nginx 处理 ACME 验证
  2. 下载证书
  3. 自动更新 Nginx 配置(添加 ssl 指令)
  4. reload Nginx

续期同样简单:

sudo certbot renew --dry-run

我的建议:大部分生产环境用这个模式就行。除非你对 Nginx 配置有洁癖不想让 Certbot 碰。

三种模式对比

特性StandaloneWebrootNginx 插件
续期停机⚠️ 10-30s✅ 零✅ 零
停 Nginx
改 Nginx 配置不需要需要(加 ACME location)不需要(自动管理)
自动配置 SSL
复杂度
适合场景开发测试需要完全掌控配置大部分生产环境

配置自动续期定时任务

大多数系统安装 Certbot 时会自动创建 systemd 定时器或 cron。确认一下:

# 检查 systemd 定时器
sudo systemctl list-timers | grep certbot

# 或检查 cron
sudo cat /etc/cron.d/certbot 2>/dev/null

如果都没有,手动加:

# 每天跑两次(Certbot 只在到期前 30 天内才真正续期)
echo "0 3,15 * * * root certbot renew --quiet" | sudo tee /etc/cron.d/certbot

测试:

sudo certbot renew --dry-run
# 应看到:The dry run was successful.

注意:用 Standalone 模式的话,cron 里必须带 --pre-hook--post-hook,不然 Certbot 会因为 80 端口被占用而失败。

DigiCert 商业证书也能用 ACME

Let’s Encrypt 是免费的,但如果你用的是 DigiCert 这种商业 CA,一样能通过 ACME 协议自动续期。

前置条件

  • DigiCert CertCentral 账户
  • ACME 目录 URL(Settings → ACME Directory URLs)
  • EAB 密钥对:KID + HMAC Key

注册

sudo certbot register \
  --server "https://acme.digicert.com/v2/acme/directory/" \
  --eab-kid "YOUR_EAB_KID" \
  --eab-hmac-key "YOUR_EAB_HMAC_KEY" \
  --email admin@yourdomain.com \
  --agree-tos

获取证书(三种模式都行)

# Nginx 插件模式
sudo certbot --nginx \
  --server "https://acme.digicert.com/v2/acme/directory/" \
  -d yourdomain.com

后续续期跟 Let’s Encrypt 完全一样,certbot renew 会自动用 DigiCert 的 ACME 服务器。

实战建议

  1. 能用 ACM 就用 ACM:如果架构允许(ALB/CloudFront/API Gateway),证书管理这种事没必要自己折腾
  2. 不得不自建就用 Nginx 插件模式:一条命令搞定,后续零维护
  3. 监控别忘了:加个 CloudWatch 自定义指标监控证书到期时间,提前告警
  4. 测试环境先跑一遍:别直接在生产上搞。--dry-run 是你的好朋友
  5. 备份私钥/etc/letsencrypt/ 目录定期备份,实例挂了还能恢复

写在后面

证书有效期缩短这事已经板上钉钉了。2026 年 3 月开始 200 天,2027 年 100 天,2029 年 47 天——越往后越紧迫。趁现在还有缓冲期把自动化搞起来,别等到 47 天的时候手忙脚乱。

如果你在亚马逊云科技上跑服务,ACM 是省心方案;如果必须自建,Certbot + ACME 协议就是标准答案。本文所有操作均在 Amazon Linux 2023 + Nginx 1.28 + Certbot 2.6 上实测验证过。


参考资料

更多推荐