Certbot 证书管理
Certbot 是 Let's Encrypt 官方的 ACME 客户端,用于自动化申请和续期免费 HTTPS/TLS 证书。一行命令搞定从申请到部署的完整流程。
速查卡片
| 项目 | 内容 |
|---|---|
| 安装 | apt install certbot / snap install certbot / brew install certbot |
| 申请+安装 | certbot --nginx -d example.com |
| 只申请不安装 | certbot certonly --webroot -w /var/www/html -d example.com |
| 通配符证书 | certbot certonly --dns-cloudflare -d *.example.com |
| 批量续期 | certbot renew(systemd timer 自动执行) |
| 测试续期 | certbot renew --dry-run |
| 查看证书 | certbot certificates |
| 吊销证书 | certbot revoke --cert-name example.com |
| 证书路径 | /etc/letsencrypt/live/<域名>/ |
| 配置文件 | /etc/letsencrypt/cli.ini |
| 续期 Hook | --deploy-hook "systemctl reload nginx" |
| 速率限制 | 50 证书/注册域/周、5 重复证书/周、5 次验证失败/小时 |
| 测试环境 | --test-cert(staging,不计入速率限制) |
概述
Certbot 是什么
Certbot 是 EFF(电子前哨基金会)维护的 Let's Encrypt 官方命令行客户端。它实现了 ACME(Automated Certificate Management Environment)协议,能够:
- 自动向 Let's Encrypt CA 证明你对域名的控制权
- 获取浏览器信任的 HTTPS 证书
- 自动安装证书到 Web 服务器(Nginx / Apache)
- 跟踪证书到期时间并自动续期
- 吊销不再需要的证书
Let's Encrypt 是由 ISRG 运营的免费、自动化、开放的证书颁发机构,签发的证书被所有主流浏览器信任。证书有效期 90 天,需要定期续期。
ACME 验证原理
申请证书前,Let's Encrypt 需要验证你确实控制着该域名。验证通过两种"挑战"(Challenge)完成:
| 挑战类型 | 原理 | 端口 | 支持通配符 |
|---|---|---|---|
| HTTP-01 | 在 /.well-known/acme-challenge/ 下放置验证文件 | 80 | ❌ |
| DNS-01 | 在 DNS 中添加 _acme-challenge TXT 记录 | 53 | ✅ |
Certbot 通过各种插件自动完成这些挑战,无需手动操作。
安装
Ubuntu / Debian
# 推荐:通过 snap 安装(官方推荐方式)
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 或通过 apt(版本可能较旧)
sudo apt update
sudo apt install certbot python3-certbot-nginxCentOS / RHEL / Fedora
# RHEL 8+ / CentOS Stream / Fedora
sudo dnf install certbot python3-certbot-nginx
# RHEL 7 / CentOS 7
sudo yum install epel-release
sudo yum install certbot python3-certbot-nginxmacOS
brew install certbotDocker
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
-p 80:80 \
certbot/certbot certonly --standalone -d example.com当前版本:5.7.0(2026 年 7 月)。可通过
certbot --version查看本地版本。
核心子命令
Certbot 通过子命令(subcommand)区分操作类型:
run — 申请并安装证书
# 自动检测 Web 服务器并申请+安装
certbot
# 指定 Nginx,申请证书并自动修改 nginx 配置
certbot --nginx -d example.com -d www.example.com
# 指定 Apache
certbot --apache -d example.comrun 是默认子命令,可以省略。这是最常用的命令——一步完成域名验证、证书申请和服务器配置。
certonly — 只申请证书不安装
# webroot 方式(不中断 Web 服务器)
certbot certonly --webroot -w /var/www/html -d example.com
# standalone 方式(临时启动内置 Web 服务器)
certbot certonly --standalone -d example.com
# DNS 方式(通配符证书必须用这个)
certbot certonly --dns-cloudflare -d *.example.com -d example.com适用场景:证书文件需要手动配置到 Web 服务器、或 Web 服务器不支持自动安装。
renew — 批量续期
# 续期所有即将过期的证书
certbot renew
# 模拟续期(不实际续期,测试流程是否正常)
certbot renew --dry-run
# 强制续期(不管是否快到期)
certbot renew --force-renewal
# 静默续期(适合 cron)
certbot renew --quietrenew 只会续期距到期 30 天内的证书。大多数发行版安装 Certbot 后会自动配置 systemd timer 或 cron job。--dry-run 使用 staging 环境测试,不计入速率限制。
管理类子命令
# 查看所有证书及其到期时间
certbot certificates
# 吊销证书
certbot revoke --cert-name example.com
# 删除证书(先吊销再删除更安全)
certbot delete --cert-name example.com
# 为已有证书追加安全增强(如 HSTS、OCSP Stapling)
certbot enhance --nginx -d example.com
# 修改证书的续期配置(v2.3.0+)
certbot reconfigure --cert-name example.com验证方式与插件
Certbot 通过"插件"来执行 ACME 挑战。插件分为两种角色:Authenticator(验证域名所有权)和 Installer(安装证书到服务器)。
插件速查
| 插件 | 验证 | 安装 | 验证方式 | 说明 |
|---|---|---|---|---|
| nginx | ✅ | ✅ | HTTP-01 (80) | 自动修改 Nginx 配置 |
| apache | ✅ | ✅ | HTTP-01 (80) | 自动修改 Apache 配置 |
| webroot | ✅ | ❌ | HTTP-01 (80) | 在网站根目录放验证文件 |
| standalone | ✅ | ❌ | HTTP-01 (80) | 临时启动内置 Web 服务器 |
| DNS 插件 | ✅ | ❌ | DNS-01 (53) | 通过 DNS API 自动添加记录 |
| manual | ✅ | ❌ | HTTP-01 / DNS-01 | 手动完成验证步骤 |
Nginx 插件
# 基本用法
certbot --nginx -d example.com -d www.example.com⚠️ Nginx 插件会自动修改 Nginx 配置文件,具体操作包括:
- 在对应
server块中添加listen 443 ssl指令 - 写入
ssl_certificate和ssl_certificate_key指向证书文件 include /etc/letsencrypt/options-ssl-nginx.conf(SSL 安全参数)- 如果使用
--redirect,自动添加 HTTP → HTTPS 重定向
防范措施:
# 建议操作前先备份
cp -r /etc/nginx /etc/nginx.bak
# 如果配置被改乱了,可以用 rollback 回滚
certbot --nginx rollback非标准 Nginx 路径可能识别失败,此时可以在 cli.ini 中指定:
nginx-server-root = /usr/local/nginx/conf
nginx-ctl = /usr/local/nginx/sbin/nginxWebroot 插件
适合已有 Web 服务器运行中、不想中断服务的场景:
# 单域名
certbot certonly --webroot -w /var/www/html -d example.com
# 多域名,每个域名可能在不同目录
certbot certonly --webroot \
-w /var/www/example -d example.com -d www.example.com \
-w /var/www/other -d other.example.com原理:Certbot 在 {webroot-path}/.well-known/acme-challenge/ 下放置一个临时验证文件,Let's Encrypt 验证服务器通过 HTTP 请求该文件来确认域名控制权。
确保 Web 服务器允许访问
/.well-known/隐藏目录。Nginx 默认允许,Apache 可能需要额外配置。
Standalone 插件
适合没有 Web 服务器运行的情况,Certbot 会临时启动一个内置 Web 服务器:
# 需要先停止占用 80 端口的服务
systemctl stop nginx
certbot certonly --standalone -d example.com
systemctl start nginx必须绑定 80 端口,所以需要先停掉占用该端口的服务。如果 80 端口被占用,也可以指定其他端口但需要防火墙配合。
DNS 插件
DNS 插件通过 API 自动修改 DNS 记录来完成 DNS-01 挑战,是获取通配符证书的唯一方式。
以 Cloudflare 为例:
# 1. 安装 DNS 插件
sudo apt install python3-certbot-dns-cloudflare
# 2. 创建 API token 配置文件(权限:Zone:DNS:Edit)
cat > ~/.secrets/cloudflare.ini << EOF
dns_cloudflare_api_token = 你的Cloudflare_API_Token
EOF
chmod 600 ~/.secrets/cloudflare.ini
# 3. 申请通配符证书
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d *.example.com -d example.com支持的主流 DNS 插件:certbot-dns-cloudflare、certbot-dns-route53(AWS)、certbot-dns-digitalocean、certbot-dns-google、certbot-dns-rfc2136 等。
组合使用插件
可以将验证和安装分离,使用不同的插件:
# webroot 验证 + nginx 安装
certbot run -a webroot -i nginx -w /var/www/html -d example.com
# DNS 验证 + apache 安装
certbot run -a dns-cloudflare -i apache -d example.comManual 手动模式
certbot certonly --manual -d example.comCertbot 会给出提示,要求你手动完成验证(放置文件或添加 DNS 记录)。⚠️ 手动模式创建的证书不支持自动续期,除非配合 --manual-auth-hook 使用自动化脚本。
证书管理
证书文件路径
申请成功后,证书存放在 /etc/letsencrypt/live/<证书名>/:
/etc/letsencrypt/live/example.com/
├── cert.pem ← 证书(不含中间证书)
├── chain.pem ← 中间证书
├── fullchain.pem ← 完整证书链(cert.pem + chain.pem) ← Nginx 用这个
├── privkey.pem ← 私钥
└── README ← 说明文件(实际是符号链接)这些文件实际是指向
/etc/letsencrypt/archive/的符号链接。不要移动或删除 archive 下的源文件。
Nginx 配置示例
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 安全参数(Certbot 自动生成的推荐配置)
include /etc/letsencrypt/options-ssl-nginx.conf;
# OCSP Stapling
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
}查看证书信息
# 查看所有 Certbot 管理的证书及到期时间
certbot certificates
# 查看单个证书详情
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout修改证书域名
# 为已有证书追加域名(会重新申请)
certbot --nginx --cert-name example.com -d example.com -d www.example.com -d api.example.com
# 如果希望自动扩展,使用 --expand
certbot --nginx --expand -d example.com -d www.example.com -d api.example.comRSA 与 ECDSA 密钥
| 参数 | 说明 |
|---|---|
--key-type rsa | 指定 RSA 密钥 |
--key-type ecdsa | 指定 ECDSA 密钥(v5.x 起默认值) |
--rsa-key-size 4096 | RSA 密钥长度(默认 2048) |
--elliptic-curve secp256r1 | ECDSA 曲线(默认 secp256r1) |
# 申请 RSA 4096 位证书
certbot --nginx --key-type rsa --rsa-key-size 4096 -d example.com
# ECDSA(默认,无需指定)
certbot --nginx -d example.comECDSA 密钥更小、更快、更安全,现在已是 Certbot 默认选项。如果目标客户端较老(Android 4.x 等),用 RSA 兼容性更好。
自动续期
systemd timer(推荐)
大多数通过系统包管理器安装的 Certbot 会自动创建 systemd timer:
# 检查 timer 状态
systemctl status certbot.timer
systemctl list-timers | grep certbot
# 手动触发
systemctl start certbot.service
# timer 配置文件位置
systemctl cat certbot.timer每天运行两次(随机时间),只续期 30 天内到期的证书。
cron 手动配置
# 编辑 root crontab
sudo crontab -e
# 每天凌晨 3:15 和下午 3:15 各执行一次
15 3,15 * * * certbot renew --quiet --post-hook "systemctl reload nginx"使用随机分钟数(0-59),避免所有 Let's Encrypt 客户端同时请求。
测试续期流程
# 不实际续期,验证流程是否正常(强烈推荐先跑一遍)
certbot renew --dry-run--dry-run 使用 staging 环境,不计入生产速率限制,如果成功输出 Congratulations, all simulated renewals succeeded 就说明续期配置没问题。
续期 Hook 体系
Certbot 提供了三层 Hook,精确控制续期前后的行为:
| Hook | 触发时机 | 适用场景 |
|---|---|---|
--pre-hook | 续期前 | 停止 Web 服务器(standalone 模式需要) |
--post-hook | 续期后(无论成败) | 重启 Web 服务器 |
--deploy-hook | 每次证书成功续期后 | 重载 Nginx、复制证书到其他位置 |
# standalone 模式续期:先停 Nginx,续完再启动
certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
# 续期成功后重载 Nginx(推荐)
# 方式一:命令行参数
certbot renew --deploy-hook "systemctl reload nginx"
# 方式二:deploy 钩子目录(可放多个脚本)
# 在 /etc/letsencrypt/renewal-hooks/deploy/ 下放可执行脚本
cat > /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh
--deploy-hook只在证书确实续期成功时执行。--post-hook不管成败都执行。
续期配置文件
每个证书的续期配置独立存放在 /etc/letsencrypt/renewal/<证书名>.conf:
# /etc/letsencrypt/renewal/example.com.conf
version = 2.8.1
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem
# 续期参数
authenticator = nginx
installer = nginx
key_type = ecdsa
# 自定义 hook
deploy_hook = systemctl reload nginx修改后可通过 certbot reconfigure --cert-name example.com 或直接编辑该文件。
通配符证书
Let's Encrypt 支持通配符证书(*.example.com),但只能通过 DNS-01 验证。
完整流程(Cloudflare)
# 1. 安装插件
sudo apt install python3-certbot-dns-cloudflare
# 2. 配置 API token
# Cloudflare 控制台 → 个人资料 → API 令牌 → 创建令牌
# 权限:Zone - DNS - Edit
# 区域资源:指定域名
cat > ~/.secrets/cloudflare.ini << EOF
dns_cloudflare_api_token = 你的API_Token
EOF
chmod 600 ~/.secrets/cloudflare.ini
# 3. 申请通配符 + 根域名
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d example.com -d *.example.com
# 4. 配置 Nginx 使用同一个证书
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;通配符续期注意事项
# DNS 插件的证书自动续期没问题(systemd timer 自动执行)
# 但如果 API token 过期,续期会失败——确保 token 长期有效
# 可以给续期添加通知 hook
certbot renew --deploy-hook "curl -X POST https://你的告警Webhook"Let's Encrypt 速率限制
Let's Encrypt 对证书申请有严格的速率限制,用令牌桶算法实现。开发和测试时务必使用 --test-cert 指向 staging 环境。
核心限制一览
| 限制项 | 额度 | 时间窗口 | 说明 |
|---|---|---|---|
| 每个注册域名的证书数 | 50 | 7 天 | 每 202 分钟恢复 1 个额度 |
| 相同域名组合的重复证书 | 5 | 7 天 | 每 34 小时恢复 1 个额度 |
| 验证失败次数 | 5 | 1 小时 | 每个账户每个域名单独计算 |
| 每个账户的订单数 | 300 | 3 小时 | 每 36 秒恢复 1 个 |
| 每个 IP 注册账户数 | 10 | 3 小时 | — |
最容易踩的坑
1. 重复证书限制(5次/7天)
最常见的原因:测试时反复运行 certbot --nginx -d example.com,每次都会申请完全相同域名组合的新证书。
# ❌ 反复申请同一个域名组合
certbot --nginx -d example.com # 第1次 OK
certbot --nginx -d example.com # 第2次 OK
certbot --nginx -d example.com # ...
# ...第6次 → 触发限制!
# ✅ 测试时使用 staging 环境
certbot --nginx --test-cert -d example.com
# ✅ 已申请过就用 renew,不会重复申请
certbot renew2. 验证失败限制(5次/小时)
# 每次失败的申请都消耗额度
# 比如端口 80 没开放,反复尝试 5 次后会被锁 1 小时
# ✅ 先用 --dry-run 验证流程
certbot certonly --dry-run --webroot -w /var/www/html -d example.com
# ✅ 排查问题期间用 staging
certbot --test-cert --nginx -d example.com3. 续期不受重复证书限制
续期(renew)操作不会触发"重复证书"限制,可以放心配置自动续期。
规避策略
- 开发/测试:一律使用
--test-cert(staging 环境,限制大幅放宽) - 多子域名:尽量合并到一个证书(SAN),而不是分别申请
- 先 dry-run:正式申请前先用
--dry-run跑一遍 - 别频繁删除重建:删除再申请 = 新证书,不是续期
常见排错
Nginx 配置被改乱了
Certbot 的 nginx 插件会自动修改 /etc/nginx/ 下的配置文件。如果出现问题:
# 方法一:rollback 回滚
certbot --nginx rollback
# 方法二:手动还原备份
cp /etc/nginx.bak/nginx.conf /etc/nginx/nginx.conf
nginx -t && systemctl reload nginx如果之前没有备份,检查 /etc/letsencrypt/ 不会影响 nginx 原始配置——Certbot 修改的是 nginx 的 server 块内容,证书文件路径是独立管理的。
端口 80 不可达
Error: Could not bind to IPv4 or IPv6 port 80原因:端口 80 被占用、防火墙拦截、或 ISP 屏蔽。
# 检查端口占用
ss -tlnp | grep :80
# 解决方式一:用 webroot(不需要绑定端口)
certbot certonly --webroot -w /var/www/html -d example.com
# 解决方式二:用 DNS 验证
certbot certonly --dns-cloudflare -d example.com
# 解决方式三:停掉占用 80 端口的服务后,standalone
systemctl stop nginx
certbot certonly --standalone -d example.com
systemctl start nginx速率限制触发
too many certificates already issued for exact set of domains# 先看当前有哪些证书
certbot certificates
# 等限制恢复(无法加速),或者:
# 1. 给域名组合加个子域名(改变 "exact set" 即可绕过)
certbot --nginx -d example.com -d www.example.com -d temp.example.com
# 2. 用 staging 环境继续测试
certbot --nginx --test-cert -d example.comDNS 验证超时
DNS problem: looking up TXT for _acme-challenge.example.comDNS 记录传播需要时间。DNS 插件的厂商 API 通常会等待传播完成,但如果用 --manual 手动添加 TXT 记录:
# 添加记录后等 5-20 分钟后按 Enter 继续
# 可以先用 dig 确认记录已生效:
dig _acme-challenge.example.com TXT续期失败但不影响服务
Attempting to renew cert ... produced an unexpected error续期失败时,已有证书在到期前仍然有效。有充足时间排查:
# 查看哪个证书续期失败
certbot renew --dry-run
# 单独续期该证书看详细错误
certbot renew --cert-name example.com --force-renewal -v
# 常见原因:
# - Nginx 配置有问题 → nginx -t 检查
# - 域名 DNS 解析变了
# - 验证路径不可达(检查防火墙/安全组 80/443 端口)Apache/Nginx 插件未检测到
# certbot 找不到你的 Web 服务器
# 指定正确的服务器根路径:
certbot --apache --apache-server-root /usr/local/apache2
certbot --nginx --nginx-server-root /usr/local/nginx/conf最佳实践
密钥类型选择
| 场景 | 推荐 | 原因 |
|---|---|---|
| 现代 Web 应用(2020+) | ECDSA(默认) | 更快、更小、更安全 |
| 需要兼容老设备 | RSA 2048 | Android 4.x / IE11 等 |
| 高安全要求 | RSA 4096 | 合规要求 |
DNS API 凭证安全
# ✅ 用范围最小的 API token,不是全局 API key
# Cloudflare:Zone:DNS:Edit 权限,只限于特定域名
# Route53:IAM 策略限制到特定 hosted zone
# ✅ 配置文件权限
chmod 600 ~/.secrets/cloudflare.ini
# ❌ 不要把凭证放 /etc/letsencrypt/cli.ini(全局可读!)通配符 vs 多域名 SAN
| 通配符 | 多域名 SAN | |
|---|---|---|
| 示例 | *.example.com | a.example.com, b.example.com |
| 验证方式 | 必须 DNS-01 | HTTP-01 即可 |
| 覆盖范围 | 所有子域名(仅一级) | 精确指定的域名 |
| 安全影响 | 私钥泄露影响所有子域名 | 影响范围可控 |
| 推荐 | 子域名多且动态变化 | 子域名固定且数量少 |
证书到期监控
# 方式一:cron 定期检查
# 每天凌晨检查,30 天内到期发告警
0 0 * * * certbot certificates 2>/dev/null | grep -q "VALID: [0-9]\{1,2\} days" && \
echo "Certificate expiring soon!" | mail -s "SSL Alert" admin@example.com全局配置文件
在 /etc/letsencrypt/cli.ini 中设置默认参数,避免每次手动指定:
# 默认同意协议
agree-tos = true
# 通知邮箱
email = admin@example.com
# RSA 密钥长度
rsa-key-size = 2048
# 默认使用 webroot 验证
authenticator = webroot
# HTTP 端口(非标端口)
http-01-port = 8080来源
| 来源 | 链接 |
|---|---|
| Certbot 官方文档 | https://eff-certbot.readthedocs.io/en/stable/ |
| Let's Encrypt 速率限制 | https://letsencrypt.org/docs/rate-limits/ |
| ACME 挑战类型 | https://letsencrypt.org/docs/challenge-types/ |
| Certbot 源码 | https://github.com/certbot/certbot |
| 版本 | 5.7.0(整理时最新稳定版) |