Certbot SSL 证书管理 & Cloudflare API 验证 🔐

🌐 使用 Cloudflare DNS API 自动验证和续签 SSL 证书,无需开放服务器端口 - 安全、高效、自动化的证书管理解决方案


📋 目录


🎯 简介

Certbot 是由 EFF (Electronic Frontier Foundation) 开发的免费开源工具,用于自动化管理和部署 Let’s Encrypt SSL 证书。

🌟 Cloudflare API 验证的优势

  • 无需开放端口:不需要开放 80/443 端口,增强服务器安全性
  • 支持通配符:可以申请 *.example.com 通配符证书,保护所有子域名
  • 完全自动化:支持无人值守自动续签,减少人工干预
  • 安全可靠:使用 API Token 而非全局密钥,遵循最小权限原则
  • DNS 验证:通过 DNS TXT 记录验证域名所有权,适用于各种服务器环境
  • 多域名支持:单张证书可包含多个域名和通配符

🔗 相关链接


📦 安装配置

🐧 安装 Certbot 和 Cloudflare 插件

Ubuntu/Debian 系统

1
2
3
4
5
6
7
8
9
# 更新系统包列表
sudo apt update

# 安装 Certbot 和 Cloudflare DNS 插件
sudo apt install -y certbot python3-certbot-dns-cloudflare

# 验证安装
certbot --version
python3 -c "import certbot_dns_cloudflare; print('✅ Cloudflare plugin installed')"

CentOS/RHEL 系统

1
2
3
4
5
6
7
8
9
10
11
# 启用 EPEL 仓库
sudo yum install -y epel-release

# 或者对于 CentOS 8/RHEL 8
sudo dnf install -y epel-release

# 安装 Certbot 和 Cloudflare DNS 插件
sudo yum install -y certbot python3-certbot-dns-cloudflare

# 或者使用 pip 安装
sudo pip3 install certbot certbot-dns-cloudflare

使用 Snap 安装(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 安装 Snap
sudo apt install -y snapd

# 确保 Snap 是最新的
sudo snap install core
sudo snap refresh core

# 安装 Certbot
sudo snap install --classic certbot

# 创建符号链接
sudo ln -s /snap/bin/certbot /usr/bin/certbot

# 安装 Cloudflare DNS 插件
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

# 验证安装
certbot --version

📁 创建配置目录

1
2
3
4
5
6
7
# 创建配置目录
sudo mkdir -p /etc/letsencrypt
sudo chmod 700 /etc/letsencrypt

# 创建日志目录
sudo mkdir -p /var/log/letsencrypt
sudo chmod 755 /var/log/letsencrypt

🔑 Cloudflare API 设置

🎯 获取 Cloudflare API Token

  1. 登录 Cloudflare 控制台: https://dash.cloudflare.com/
  2. 进入 API Tokens: 点击右上角用户图标 → My Profile → API Tokens
  3. 创建 Token: 点击 “Create Token” → 使用 “Edit zone DNS” 模板
  4. 配置权限:
    • 权限: Zone - DNS - Edit
    • 资源: Include - All zones (或指定特定域名)
  5. 创建并保存 Token: 复制生成的 API Token

📝 创建配置文件

1
2
3
4
5
6
7
8
9
10
11
12
# 创建 Cloudflare 配置文件
sudo tee /etc/letsencrypt/cloudflare.ini > /dev/null <<'EOF'
# Cloudflare API credentials used by Certbot
dns_cloudflare_api_token = YOUR_API_TOKEN_HERE
EOF

# 设置严格权限
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo chown root:root /etc/letsencrypt/cloudflare.ini

# 验证配置文件
sudo cat /etc/letsencrypt/cloudflare.ini

⚠️ 重要:

  • 使用 API Token 时只需配置 dns_cloudflare_api_token,不需要 dns_cloudflare_api_keydns_cloudflare_email
  • YOUR_API_TOKEN_HERE 替换为实际的 API Token
  • 确保配置文件权限为 600,防止其他用户读取

📝 证书申请

🚀 申请通配符证书

1
2
3
4
5
6
7
8
9
10
11
# 申请通配符证书
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
--preferred-challenges dns-01 \
-d "example.com" \
-d "*.example.com" \
--register-unsafely-without-email \
--agree-tos \
--non-interactive

📋 参数说明

  • --dns-cloudflare: 使用 Cloudflare DNS 验证
  • --dns-cloudflare-credentials: 指定凭证文件路径
  • --dns-cloudflare-propagation-seconds 60: 等待 DNS 传播的时间(秒)
  • --preferred-challenges dns-01: 优先使用 DNS 挑战验证
  • -d: 指定域名(支持多个域名)
  • --register-unsafely-without-email: 不提供邮箱(可选)
  • --agree-tos: 同意服务条款
  • --non-interactive: 非交互模式,适合脚本运行

🎯 申请多域名证书

1
2
3
4
5
6
7
8
9
10
# 申请包含多个域名的证书
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "example.com" \
-d "www.example.com" \
-d "api.example.com" \
-d "*.staging.example.com" \
--register-unsafely-without-email \
--agree-tos

✅ 验证申请结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看证书信息
sudo certbot certificates

# 检查证书文件
sudo ls -la /etc/letsencrypt/live/example.com/

# 验证证书内容
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout | head -20

# 检查证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates

# 验证证书链
sudo openssl verify -CAfile /etc/letsencrypt/live/example.com/chain.pem /etc/letsencrypt/live/example.com/cert.pem


⚡ 自动续签

🕐 计划任务配置

方法一:简单续签命令

1
2
3
4
5
6
7
8
9
# 编辑 crontab
sudo crontab -e

# 添加以下内容:
# 每天凌晨 2:30 自动续签(如果证书30天内过期)
30 2 * * * /usr/bin/certbot renew --quiet --renew-hook "systemctl reload nginx"

# 或者使用绝对路径
30 2 * * * /usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload nginx"

方法二:智能续签脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 创建智能续签脚本
sudo tee /usr/local/bin/certbot-renew-smart.sh > /dev/null <<'EOF'
#!/bin/bash
# 智能证书续签脚本

DOMAIN="example.com"
LOG_FILE="/var/log/certbot-renew.log"
CONFIG_FILE="/etc/letsencrypt/cloudflare.ini"
NGINX_CONFIG="/etc/nginx/sites-available/default"

echo "$(date): 开始证书续签检查" >> $LOG_FILE

# 检查证书是否存在
if [ ! -f "/etc/letsencrypt/live/$DOMAIN/cert.pem" ]; then
echo "错误: 证书文件不存在" >> $LOG_FILE
exit 1
fi

# 检查证书有效期
EXPIRY_DAYS=$(sudo certbot certificates | grep -A 3 "$DOMAIN" | grep "EXPIRY" | awk '{print $6}' | cut -d')' -f1)
if [ -z "$EXPIRY_DAYS" ] || [ "$EXPIRY_DAYS" -le 10 ]; then
echo "证书即将过期(剩余 ${EXPIRY_DAYS:-未知} 天),尝试续签..." >> $LOG_FILE

# 执行续签
if sudo certbot renew --dns-cloudflare --dns-cloudflare-credentials $CONFIG_FILE --force-renewal; then
echo "证书续签成功" >> $LOG_FILE

# 检查 Nginx 配置语法
if sudo nginx -t; then
# 重载 Nginx
sudo systemctl reload nginx
echo "Nginx 配置已重载" >> $LOG_FILE
else
echo "错误: Nginx 配置测试失败" >> $LOG_FILE
fi
else
echo "证书续签失败" >> $LOG_FILE
exit 1
fi
else
echo "证书有效期剩余 ${EXPIRY_DAYS} 天,无需续签" >> $LOG_FILE
fi

echo "$(date): 证书检查完成" >> $LOG_FILE
EOF

# 设置脚本权限
sudo chmod +x /usr/local/bin/certbot-renew-smart.sh
sudo chown root:root /usr/local/bin/certbot-renew-smart.sh

📅 添加计划任务

1
2
3
4
5
6
7
8
# 编辑 root 的 crontab
sudo crontab -e

# 添加智能续签任务(每天凌晨3点执行)
0 3 * * * /usr/local/bin/certbot-renew-smart.sh >> /var/log/certbot-renew.log 2>&1

# 添加日志清理任务(每月清理一次旧日志)
0 2 1 * * find /var/log -name "certbot*.log" -mtime +30 -delete

🔔 续签通知配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 添加邮件通知功能到续签脚本
sudo tee -a /usr/local/bin/certbot-renew-smart.sh > /dev/null <<'EOF'

# 发送通知函数
send_notification() {
local subject="$1"
local message="$2"
# 使用 mail 命令发送邮件
echo "$message" | mail -s "$subject" admin@example.com
# 或者使用其他通知方式(如 Slack、Telegram 等)
}

# 在适当位置添加通知
if [ $? -eq 0 ]; then
send_notification "证书续签成功" "域名 $DOMAIN 的 SSL 证书已成功续签。"
else
send_notification "证书续签失败" "域名 $DOMAIN 的 SSL 证书续签失败,请检查日志。"
fi
EOF

🔧 维护管理

📋 常用管理命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看所有证书
sudo certbot certificates

# 检查证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates

# 测试续签(不实际执行)
sudo certbot renew --dry-run

# 强制续签特定证书
sudo certbot renew --cert-name example.com --force-renewal

# 查看 Certbot 日志
sudo tail -f /var/log/letsencrypt/letsencrypt.log

# 查看证书详细信息
sudo certbot show --cert-name example.com

🔄 手动同步证书到 Web 服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 同步证书到 Nginx
sudo cp -f /etc/letsencrypt/live/example.com/fullchain.pem /etc/nginx/ssl/example.com.crt
sudo cp -f /etc/letsencrypt/live/example.com/privkey.pem /etc/nginx/ssl/example.com.key

# 设置正确权限
sudo chmod 644 /etc/nginx/ssl/example.com.crt
sudo chmod 600 /etc/nginx/ssl/example.com.key
sudo chown www-data:www-data /etc/nginx/ssl/example.com.*

# 测试 Nginx 配置
sudo nginx -t

# 重载 Nginx
sudo systemctl reload nginx

# 对于 Apache
sudo cp -f /etc/letsencrypt/live/example.com/fullchain.pem /etc/ssl/certs/example.com.crt
sudo cp -f /etc/letsencrypt/live/example.com/privkey.pem /etc/ssl/private/example.com.key
sudo systemctl reload apache2

🗑️ 撤销和删除证书

1
2
3
4
5
6
7
8
9
10
# 撤销证书
sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem --reason superseded

# 删除证书配置
sudo certbot delete --cert-name example.com

# 手动删除证书文件
sudo rm -rf /etc/letsencrypt/archive/example.com
sudo rm -rf /etc/letsencrypt/live/example.com
sudo rm -rf /etc/letsencrypt/renewal/example.com.conf

🔍 故障排除命令

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查 DNS 解析
dig TXT _acme-challenge.example.com

# 调试模式运行 Certbot
sudo certbot --debug --verbose certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini -d example.com

# 检查 Cloudflare API 连接
curl -X GET "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"

# 检查证书透明度日志
curl "https://crt.sh/?q=example.com&output=json" | jq .

🗑️ 完全卸载

🔄 卸载 Certbot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 停止所有 Certbot 相关进程
sudo systemctl stop certbot.timer
sudo systemctl disable certbot.timer

# 卸载软件包(APT)
sudo apt remove --purge -y certbot python3-certbot-dns-cloudflare

# 卸载软件包(Snap)
sudo snap remove certbot certbot-dns-cloudflare
sudo rm -f /usr/bin/certbot

# 清理配置文件
sudo rm -rf /etc/letsencrypt/
sudo rm -rf /var/lib/letsencrypt/
sudo rm -rf /var/log/letsencrypt/

# 清理 Cron 任务
sudo crontab -l | grep -v certbot | sudo crontab -

# 删除脚本文件
sudo rm -f /usr/local/bin/certbot-renew-smart.sh

# 清理残留包
sudo apt autoremove -y
sudo apt clean

📊 验证卸载

1
2
3
4
5
6
7
# 检查是否完全卸载
which certbot || echo "✅ Certbot 已卸载"
ls /etc/letsencrypt 2>/dev/null || echo "✅ 配置目录已清理"
ps aux | grep certbot | grep -v grep || echo "✅ 无 Certbot 进程"

# 检查已安装的 Python 模块
python3 -c "import certbot_dns_cloudflare" 2>/dev/null && echo "❌ Cloudflare 插件仍在" || echo "✅ Cloudflare 插件已移除"

💡 最佳实践

🛡️ 安全建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定期轮换 API Token(每3-6个月)
# 为每个域名创建单独的 API Token,遵循最小权限原则

# 使用强权限保护密钥文件
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo chmod 700 /etc/letsencrypt/live/
sudo chmod 755 /etc/letsencrypt/archive/

# 定期备份证书和配置
sudo tar -czvf /backup/letsencrypt-backup-$(date +%Y%m%d).tar.gz /etc/letsencrypt/

# 监控证书目录的更改
sudo apt install -y auditd
sudo auditctl -w /etc/letsencrypt/ -p wa -k letsencrypt

📊 监控和告警

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 证书过期监控脚本
#!/bin/bash
DOMAIN="example.com"
WARNING_DAYS=14
ADMIN_EMAIL="admin@example.com"

EXPIRY_DATE=$(sudo openssl x509 -in /etc/letsencrypt/live/$DOMAIN/cert.pem -enddate -noout | cut -d= -f2)
EXPIRY_TS=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_TS=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_TS - CURRENT_TS) / 86400 ))

if [ $DAYS_LEFT -le $WARNING_DAYS ]; then
SUBJECT="SSL 证书过期警告: $DOMAIN"
MESSAGE="域名 $DOMAIN 的 SSL 证书将在 $DAYS_LEFT 天后过期($EXPIRY_DATE)。请及时续签。"
echo "$MESSAGE" | mail -s "$SUBJECT" "$ADMIN_EMAIL"

# 可选: 发送到 Slack 或其它通知系统
# curl -X POST -H 'Content-type: application/json' \
# --data "{\"text\":\"$MESSAGE\"}" \
# https://hooks.slack.com/services/XXX/XXX/XXX
fi

🔧 高级故障排除技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查 Let's Encrypt 速率限制
# 访问: https://letsencrypt.org/docs/rate-limits/

# 使用暂存环境测试
sudo certbot certonly --test-cert --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com

# 检查证书透明度日志
curl -s "https://crt.sh/?q=example.com&output=json" | jq -r '.[] | select(.name_value | contains("example.com")) | .not_after' | head -1

# 手动添加 DNS 记录进行验证
# 获取需要添加的 TXT 记录
sudo certbot certonly --manual --preferred-challenges dns -d example.com --dry-run

📝 更新和维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定期更新 Certbot
sudo apt update && sudo apt upgrade certbot python3-certbot-dns-cloudflare

# 或者使用 Snap 更新
sudo snap refresh certbot

# 检查插件兼容性
python3 -c "import pkg_resources; print('Cloudflare plugin version:', pkg_resources.get_distribution('certbot-dns-cloudflare').version)"

# 验证配置语法
sudo certbot renew --dry-run --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini

# 检查系统日志中的 Certbot 相关错误
sudo journalctl -u certbot | tail -50

🌐 多服务器证书同步

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用 rsync 同步证书到多个服务器
#!/bin/bash
SERVERS=("server1.example.com" "server2.example.com")
DOMAIN="example.com"

for SERVER in "${SERVERS[@]}"; do
echo "同步证书到 $SERVER..."
rsync -avz -e "ssh -p 22" \
/etc/letsencrypt/live/$DOMAIN/ \
user@$SERVER:/etc/letsencrypt/live/$DOMAIN/

ssh user@$SERVER "sudo systemctl reload nginx"
done

🎯 提示: 建议在生产环境部署前,先在测试环境验证所有配置。定期检查日志和证书状态,确保自动化流程正常运行。

📚 扩展阅读:

🔧 紧急恢复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 如果自动续签失败,手动执行
sudo /usr/local/bin/certbot-renew-smart.sh

# 检查 Nginx 配置
sudo nginx -t

# 临时恢复旧证书(如果有备份)
sudo cp -rf /backup/letsencrypt-backup/live/example.com/ /etc/letsencrypt/live/
sudo systemctl reload nginx

# 紧急情况下申请新证书
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com --force-renewal

💡 专业建议:

  1. 使用证书监控服务如 SSL Labs 定期检查证书配置
  2. 实施证书钉扎 (Certificate Pinning) 增强安全性
  3. 考虑使用双向 TLS (mTLS) 对于内部服务
  4. 定期进行安全审计和渗透测试

希望本指南能帮助您顺利使用 Certbot 和 Cloudflare API 管理 SSL 证书!🔐