架构总览
┌──────────────────────────────────────────────────────────┐
│ Certbot SSL证书管理 · Docker三文件模式 │
├────────────┼─────────────────────────────────────────────┤
│ 外部服务 │ Docker Host · ghost@oracle-linux │
├────────────┼─────────────────────────────────────────────┤
│ │ │
│ name.com │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ DNS API │ │ add.yml │ │renew.yml │ │ cli.yml │ │
│ │ │ certonly │ │ renew │ │sleep ∞ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │
│ Let's │ └───────────┼────────────┘ │
│ Encrypt │ ┌─────┴─────┐ │
│ ACME │ │ certbot │ │
│ │ │ 容器 │ │
│ │ │ ←→ DNS │ │
│ │ │ ←→ ACME │ │
│ │ └─────┬─────┘ │
│ │ │
│ │ ┌──────────────┴─────────────┐ │
│ │ │ data/letsencrypt/ │ │
│ │ │ live/ghost.atibm.com/ │ │
│ │ │ scripts/ config/ │ │
│ │ └────────────────────────────┘ │
│ │ │
│ │ ┌──────────┐ │
│ │ │ nginx │ │
│ │ │ 容器 │ │
│ │ │ 读取证书 │ │
│ │ └──────────┘ │
│ │ │
├────────────┼─────────────────────────────────────────────┤
│ Cron │ 02 08 * * * cd /www/certbot │
│ 宿主机 │ docker-compose -f renew.yml up │
│ │ docker exec nginx nginx -s reload │
└──────────────────────────────────────────────────────────┘使用 certbot 容器 + name.com DNS API 自动化插件,通过 Docker Compose 管理 SSL 证书的完整生命周期。
工作目录:/www/certbot/(宿主机 ghost 用户)
核心设计:3 个独立的 docker-compose 文件,通过不同的 entrypoint 实现不同操作,共用同一个持久化数据卷 ./data/letsencrypt。
目录结构
/www/certbot/
├── docker-compose.yml # 主文件,当前 = renew 模式(certbot renew)
├── renew.yml # 续期模式(certbot renew)
├── add.yml # 新增/重置证书模式(certbot certonly --manual ...)
├── cli.yml # 交互调试模式(sleep infinity)
├── data/
│ ├── letsencrypt/ # 证书持久化数据 ← 核心资产
│ ├── scripts/
│ │ └── certbot-dns-name-com/
│ │ └── src/certbot-dns-namecom.py # name.com DNS API hook
│ ├── config/
│ │ └── certbot-dns-namecom.config.json # name.com 账号+token(chmod 600)
│ └── log/ # certbot 日志3个Docker-Compose文件详解
三个文件共享相同的 volumes 和 network 配置,唯一区别是 entrypoint 不同。
① renew.yml — 日常续期
entrypoint: /bin/sh -c "apk add --no-cache py3-requests > /dev/null && certbot renew"
- 用途:续期所有已存在的证书,同时也是docker-compse.yml 主配置
- 行为:certbot renew 检查所有已签发证书,仅对到期前30天内的证书续期
- 使用场景:cron 定时任务、手动快速续期
- 维护域名:11个(全部域名,含 v1008081~8084 和 git)
② add.yml — 新增/重置证书
services:
certbot:
container_name: "certbot"
image: certbot/certbot:v3.1.0
restart: "no" # 不需要常驻
volumes:
- ./data/letsencrypt:/etc/letsencrypt
- ./data/scripts/certbot-dns-name-com/src/certbot-dns-namecom.py:/usr/bin/certbot-dns-namecom.py:ro
- ./data/config/certbot-dns-namecom.config.json:/etc/certbot-dns-namecom.config.json:ro
- ./data/log:/var/log
networks:
- ghost_net
# 启动后重置所维护的证书,完成后保持运行,供用户确认
entrypoint: >
/bin/sh -c "apk add --no-cache py3-requests > /dev/null &&
certbot certonly --manual --preferred-challenges dns
--manual-auth-hook '/usr/bin/certbot-dns-namecom.py add'
--manual-cleanup-hook '/usr/bin/certbot-dns-namecom.py clean'
--cert-name ghost.atibm.com
--force-renewal
--non-interactive
--agree-tos
--email abc@gmail.com
-d a.atibm.com
-d b.atibm.com
-d c.atibm.com
"
deploy:
resources:
limits:
memory: 32M
networks:
ghost_net:
external: true
- 用途:首次申请证书、增删域名后重新签发、强制刷新证书
- 行为:通过 name.com API 自动添加/清理 DNS TXT 记录完成域名验证,强制重新签发
- 与 renew 的区别:renew 不能增删域名;add 用 --force-renewal 全部重签
- 域名少的原因:只包含 8 个核心域名。如需增减域名编辑此文件
③ cli.yml — 交互调试
entrypoint: /bin/sh -c "apk add --no-cache py3-requests curl && sleep infinity"- 用途:进入容器交互式调试、手动执行 certbot 命令
- 使用方式:
docker-compose -f cli.yml up -d启动 →docker exec -it certbot sh进入 - 额外装了 curl:比另外两个文件多一个 curl,方便调试网络
- 用完记得 down:
docker-compose -f cli.yml down
生命周期操作
查看证书状态与域名清单
# 查看所有已签发证书(含证书名、域名清单、到期时间)
docker-compose run --rm --entrypoint "sh" certbot -c "certbot certificates"
# 查看证书中的 SAN 域名清单(Subject Alternative Names)
docker-compose run --rm --entrypoint "sh" certbot -c "openssl x509 -in /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem -noout -ext subjectAltName"
# 查看证书文件(live 链接指向最新版本)
docker-compose run --rm --entrypoint "ls" certbot -la /etc/letsencrypt/live/ghost.atibm.com/
# 查看证书有效期
docker-compose run --rm --entrypoint "sh" certbot -c "openssl x509 -in /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem -noout -dates"首次申请证书
仅需执行一次。之后用 renew 续期即可。
cd /www/certbot
docker-compose -f add.yml up执行后容器自动退出。证书保存到 ./data/letsencrypt/live/ghost.atibm.com/。
日常续期(手动)
cd /www/certbot
docker-compose -f renew.yml upcertbot renew 只续期距到期不足30天的证书,没到期的不会操作。
增删域名
- 编辑
add.yml,在 entrypoint 中增加/删除-d yourdomain.atibm.com行 - 执行:
docker-compose -f add.yml up
注意:使用 --force-renewal 会重新签发,letsencrypt 有速率限制(每周5次/域名)。频繁操作会被限流。
删除证书
docker-compose run --rm --entrypoint "sh" certbot -c "certbot delete --cert-name ghost.atibm.com"删除后需重新用 add.yml 申请。
Nginx 重载证书
证书更新后 nginx 不会自动加载新证书,需要 reload:
docker exec nginx nginx -s reloadrenew.yml 和 add.yml 不自动做这一步(容器执行完就退出了),需手动执行或在 cron 脚本中串联。
Cron 自动化
宿主机 crontab 每日执行证书续期,并自动 reload nginx。
当前 cron 配置
# 每周日凌晨 3 点自动续期 SSL 证书,并重启 Nginx 容器加载新证书
0 2 * * 0 cd /www/certbot && { echo "$(date) - [Start]" && docker-compose up certbot && echo "$(date) - [Nginx Reloading]" && docker exec nginx nginx -s reload && echo "$(date) - [Done]"; } >> /home/ghost/cron_certbot.log 2>&1Cron 管理
crontab -l # 查看任务
crontab -e # 编辑
systemctl status crond # 检查 cron 服务状态
systemctl restart crond # 重启 cron 服务日志查看
cat /home/ghost/cron_certbot.log # 每次执行追加的记录依赖资源
- name.com API 脚本:
git clone --depth 1 https://github.com/laonan/certbot-dns-name-com.git data/scripts/certbot-dns-name-com - name.com Token 配置:
data/config/certbot-dns-namecom.config.json(chmod 600) - API 白名单:服务器 IP 需加入 name.com API 白名单
调试技巧
# SSL 握手检查
curl -v https://4060.atibm.com 2>&1 | grep -E "SSL|certificate|subject"
# 证书链检查
openssl s_client -connect 4060.atibm.com:443 -servername 4060.atibm.com
# name.com API 连通性测试
python3 -c "import requests; r = requests.get('https://api.name.com/v4/domains/atibm.com', auth=('USERNAME', 'TOKEN')); print(r.status_code); print(r.json())"
# 模拟申请(dry-run,不实际签发)
docker-compose -f cli.yml up -d
docker exec certbot certbot certonly --manual --preferred-challenges dns \
--manual-auth-hook '/usr/bin/certbot-dns-namecom.py add' \
--manual-cleanup-hook '/usr/bin/certbot-dns-namecom.py clean' \
--cert-name ghost.atibm.com -d test.atibm.com \
--agree-tos --email cheanty@gmail.com --non-interactive \
--server https://acme-v02.api.letsencrypt.org/directory --dry-run
docker-compose -f cli.yml down注意事项
- user 配置已移除:之前设过
user: "1000:1000"导致权限问题,当前配置已去掉,以 root 运行容器 - 容器 memory 限制 32M:certbot 很轻量,足够
- restart: no:容器做完事就退,不需要保持运行(cli.yml 除外)
- renew vs add:日常只用 renew.yml;只有改域名清单时才用 add.yml
- docker-compose.yml 内容与 renew.yml 相同:是默认的快捷方式。可以删掉 docker-compose.yml,全部用 -f 指定文件
- Nginx reload 要手动做:cron 脚本中串联了
docker exec nginx nginx -s reload,手动执行续期时别忘了 - Let's Encrypt 速率限制:每周每域名 5 次证书签发。--force-renewal 会计入,不要频繁执行 add.yml
- 证书路径:nginx 通过
ghost_net网络共享,nginx 容器中也是用/etc/letsencrypt吗?需要确认 nginx 是否也映射了同一个 letsencrypt 目录