Docker使用Certbot颁发更新证书
概述
使用Docker容器运行Certbot,通过Cloudflare DNS验证方式自动化颁发和更新Let’s Encrypt SSL证书。
适用版本:Certbot 4.0.0 及以上。
准备工作
1. Cloudflare API凭证配置
创建Cloudflare API凭证文件 cloudflare.ini:
方式一:邮箱+全局API密钥(不推荐)
# Cloudflare API credentials used by Certbot
dns_cloudflare_email = user@example.com
dns_cloudflare_api_key = xxxx方式二:API令牌模式(推荐,更安全)
# Cloudflare API credentials used by Certbot
dns_cloudflare_api_token = xxxxxAPI令牌创建步骤:
- 登录Cloudflare控制台
- 进入”My Profile” → “API Tokens”
- 点击”Create Token”
- 选择”Edit zone DNS”模板
- 配置权限:Zone → DNS → Edit
- 选择要管理的域名
- 生成令牌并复制到配置文件中
2. 目录结构准备
# 创建证书存储目录
mkdir -p /data/nginx/cert
# 创建Cloudflare凭证文件
vim /data/nginx/cert/cloudflare.ini
# 设置文件权限(重要!)
chmod 600 /data/nginx/cert/cloudflare.ini颁发新证书
单次运行命令
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare certonly \
--non-interactive \
--agree-tos \
--email user@example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d host.domain.com参数说明:
--rm:容器运行后自动删除-v:挂载证书存储目录certonly:仅获取证书,不安装--non-interactive:非交互模式--agree-tos:同意服务条款--email:通知邮箱--dns-cloudflare:使用Cloudflare DNS验证-d:要申请证书的域名(可多个)
自动化更新证书
宿主机脚本方案
先确认 Nginx 容器在其 Compose 文件中使用固定名称 nginx,并确认宿主机证书目录 /data/nginx/cert 同时挂载到 Nginx 容器的 /etc/letsencrypt。
在宿主机创建 /usr/local/sbin/renew-certificates.sh:
#!/usr/bin/env bash
set -eu
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare renew \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--non-interactive \
&& docker exec nginx nginx -s reload宿主机凭据文件必须位于 /data/nginx/cert/cloudflare.ini,并执行:
chmod 600 /data/nginx/cert/cloudflare.ini
chmod 750 /usr/local/sbin/renew-certificates.sh由宿主机 root 的 crontab 每天运行脚本:
0 2 * * * /usr/local/sbin/renew-certificates.sh >> /var/log/certbot-renew.log 2>&1&& 保证 Certbot 命令失败时不会重载 Nginx。certbot renew 在本次没有证书达到续期条件时仍可能返回成功,因此 Nginx 可能执行一次无必要的 reload;它只会重新读取当前有效证书,不改变证书内容。该方案不向 Certbot 容器挂载 Docker socket,Docker 控制命令全部由宿主机执行。
Certbot Renew工作机制详解
1. 证书续期流程
Certbot执行 renew 命令时的完整流程:
1. 扫描宿主机 /data/nginx/cert/renewal/ 目录
↓
2. 读取每个证书的 renewal configuration 文件
↓
3. 检查证书剩余有效期
↓
4. 判断是否需要续期(Certbot 4.0.0 及以上在证书剩余寿命不足三分之一时续期;寿命不超过 10 天的证书在剩余不足二分之一时续期)
↓
5. 需要续期 → 执行验证流程
↓
6. 不需要续期 → 跳过2. Renewal配置文件
每个已申请证书对应一个配置文件:
/data/nginx/cert/renewal/example.com.conf文件内容包含:
- 域名列表
- 验证方式(dns-cloudflare/webroot等)
- 插件参数
- 证书路径
- 原始申请参数
3. 续期触发条件
# 查看证书过期时间
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare certificates
# 手动强制续期(即使未到期)
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare renew \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--non-interactive \
--force-renewal4. Cloudflare DNS验证流程
当证书需要续期时:
1. 调用 dns-cloudflare 插件
↓
2. 使用 cloudflare.ini 中的 API Token
↓
3. 在 Cloudflare DNS 中创建 _acme-challenge TXT 记录
↓
4. Let's Encrypt ACME 服务器查询该记录
↓
5. 验证成功后签发新证书
↓
6. 删除临时 DNS 记录证书文件结构
证书存储位置
/data/nginx/cert/
├── live/ # 当前使用的证书
│ └── example.com/
│ ├── cert.pem # 证书
│ ├── chain.pem # 中间证书
│ ├── fullchain.pem # 完整证书链
│ └── privkey.pem # 私钥
├── archive/ # 历史证书存档
│ └── example.com/
│ ├── cert1.pem
│ ├── cert2.pem
│ └── ...
└── renewal/ # 续期配置文件
└── example.com.confNginx配置示例
以下路径是宿主机 /data/nginx/cert 挂载到 Nginx 容器后的容器内路径:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 其他配置...
}常见问题与解决方案
问题1:证书续期失败
症状:宿主机续期脚本返回错误
可能原因:
- Cloudflare API Token权限不足
- 网络连接问题
- DNS记录创建失败
解决方案:
# 1. 检查API Token权限
# 2. 测试DNS记录创建
docker run --rm -v /data/nginx/cert:/etc/letsencrypt certbot/dns-cloudflare certificates
# 3. 手动测试续期(带详细日志)
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare renew \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--non-interactive \
--dry-run问题2:证书文件权限问题
症状:Nginx无法读取证书文件
解决方案:
# 设置正确的权限
chmod 755 /data/nginx/cert/live/
chmod 755 /data/nginx/cert/archive/
chmod 644 /data/nginx/cert/live/example.com/*.pem
chmod 600 /data/nginx/cert/live/example.com/privkey.pem问题3:多域名证书
申请多域名证书:
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare certonly \
--non-interactive \
--agree-tos \
--email user@example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com \
-d www.example.com \
-d api.example.com最佳实践
安全建议
- 使用API Token而非全局API密钥
- 限制API Token权限:仅授予DNS编辑权限
- 保护凭证文件:
chmod 600 cloudflare.ini - 定期轮换API Token:每3-6个月更新一次
监控建议
-
证书过期监控:
# 检查证书状态 docker run --rm \ -v /data/nginx/cert:/etc/letsencrypt \ certbot/dns-cloudflare certificates | grep -A2 "VALID" -
续期日志监控:
# 查看宿主机 cron 写入的续期日志 tail -f /var/log/certbot-renew.log -
设置告警:证书剩余天数<15天时发送通知
备份策略
-
备份证书文件:
# 备份宿主机证书目录 tar -czf /backup/letsencrypt-$(date +%Y%m%d).tar.gz /data/nginx/cert/ -
备份Cloudflare凭证:安全存储cloudflare.ini文件
扩展功能
通配符证书
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare certonly \
--non-interactive \
--agree-tos \
--email user@example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "*.example.com" \
-d example.com测试环境使用
# 使用Let's Encrypt测试环境(避免频率限制)
docker run --rm \
-v /data/nginx/cert:/etc/letsencrypt \
certbot/dns-cloudflare certonly \
--test-cert \
--non-interactive \
--agree-tos \
--email user@example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.comObsidian关联
相关笔记
- Nginx配置与优化 - 如何配置Nginx使用Certbot生成的SSL证书
- 系统运维 - 系统运维知识库目录
反向链接
- 从Nginx配置与优化引用此笔记的SSL证书配置部分
使用场景
- Web服务器SSL自动化:与此笔记配合使用 → SSL证书配置
- Docker化部署:容器化的证书管理方案
- 生产环境部署:结合监控和备份策略
工作流程
graph TD A[准备Cloudflare API] --> B[Docker运行Certbot] B --> C[生成SSL证书] C --> D[Nginx配置证书路径] D --> E[自动化更新证书] E --> F[证书更新后重载Nginx] style A fill:#e1f5fe style C fill:#f3e5f5 style F fill:#e8f5e8