用docker容器certbot + nginx,实现let's encrypt证书自动维护的案例,来展示certbot的功能说明
现状
- docker
- nginx 连接证书
- certbot 维护证书:到期手动维护,手动调用name api修改dns配合验证,手动重载nginx
- ghost 使用证书
- trilium 使用证书
目标
- 目标一:在宿主机完成所有操作,并且简化手动命令
- 目标二:让 Certbot 自动续期 证书,不需要人工干预。
方案
- cerbot容器内使用certbot-dns-name-com的python脚本,自动配置name.com的api
- 宿主机用cron定时任务调用
docker-compose.yml
services:
certbot:
container_name: "certbot"
image: certbot/certbot:v3.1.0
restart: "no" # 需要长期挂着用unless-stopped,2周起来一次更新证书则用no
volumes:
- ./data/letsencrypt:/etc/letsencrypt
- ./data/scripts:/opt/scripts
- ./data/config:/etc/namecom
- ./data/log:/var/log
networks:
- ghost_net
# 2. 移除 sleep infinity,改为执行完安装即执行续期
entrypoint: /bin/sh -c "apk add --no-cache py3-requests > /dev/null && ln -sf /opt/scripts/certbot-dns-namecom.py /usr/bin/certbot-dns-namecom.py && certbot renew"
deploy:
resources:
limits:
memory: 32M
networks:
ghost_net:
external: true容器证书脚本部署(容器常驻,unless-stopped模式,去掉entrypoint)
- certbot容器升级
- 查看版本:
docker exec -it certbot certbot --version - 脚本升级:
docker exec -it certbot pip install --upgrade certbot - 容器升级:修改docker-compose.yml里的certbot版本号,down容器,再up -d\
- 查看版本:
- name域名脚本token配置
- token配置文件(重建):
docker exec -i certbot sh -c "echo '{\"namecom\": {\"username\": \"your_namecom_username\", \"token\": \"your_api_token\"}, \"waitsec\": 15}' > /etc/certbot-dns-namecom.config.json" - 配置文件权限(重建):
docker exec -it certbot chmod 600 /etc/certbot-dns-namecom.config.json - 白名单:将服务器ip加入name api的白名单
- token配置文件(重建):
- name域名脚本
- 升级PIP(重建):
docker exec -it certbot /usr/local/bin/python -m pip install --upgrade pip - 拉取脚本(重建):
docker exec -it certbot sh -c "apk add git && git clone https://github.com/laonan/certbot-dns-name-com /opt/certbot-dns-name-com" - 安装依赖(重建):docker exec -it certbot pip install requests
- 设置脚本(重建):docker exec -it certbot sh -c "cp /opt/certbot-dns-name-com/src/certbot-dns-namecom.py /usr/bin/certbot-dns-namecom.py"
- 脚本权限(重建):
docker exec -it certbot chmod +x /usr/bin/certbot-dns-namecom.py - 测试脚本:直接运行后面的手动续期
- 升级PIP(重建):
测试容器(容器常驻,unless-stopped模式)
- 申请SSL证书
- 测试申请1个域名:
docker exec -it 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 youremail@mail.com --non-interactive --server https://acme-v02.api.letsencrypt.org/directory --dry-run - 测试申请5个域名:
docker exec -it 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 ghost.atibm.com -d atibm.com -d www.atibm.com -d trilium.atibm.com -d test.atibm.com --agree-tos --email youremail@mail.com --non-interactive --server https://acme-v02.api.letsencrypt.org/directory --dry-run - 正式申请5个域名:
docker exec -it 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 ghost.atibm.com -d atibm.com -d www.atibm.com -d trilium.atibm.com -d test.atibm.com --agree-tos --email youremail@mail.com --non-interactive --server https://acme-v02.api.letsencrypt.org/directory - 申请泛域名
- 测试申请1个域名:
- 证书维护
- 查看证书:
docker exec -it certbot certbot certificates - 证书文件:
docker exec -it certbot ls /etc/letsencrypt/live/ - 证书期限:
docker exec -it certbot openssl x509 -in /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem -noout -dates
- 查看证书:
手动操作证书(容器常驻,unless-stopped模式)
- 【查看证书】
- 直接执行:
{ echo "$(date) - [Certificate Check Start]"; echo "--- Certbot Summary ---"; docker exec certbot certbot certificates; echo "--- Precise File Dates ---"; docker exec certbot openssl x509 -in /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem -noout -dates; echo "$(date) - [Check Finished]"; } >> /home/ghost/cron_certbot.log 2>&1
- 直接执行:
- 【手动续期】同时也是权限验证
- 直接执行:
{ echo "$(date) - [Cron Start]"; docker exec certbot certbot renew && echo "$(date) - [Renew Success]" || echo "$(date) - [Renew Failed or No Need]"; echo "$(date) - [Running Nginx Reload]"; docker exec nginx nginx -s reload && echo "$(date) - [Nginx Reload Success]"; } >> /home/ghost/cron_certbot.log 2>&1- cron执行日志:
cat /home/ghost/cron_certbot.log
- cron执行日志:
- 依赖ghost用户的docker权限
- 检查用户权限:
id ghost - 增加组权限:
sudo usermod -aG docker ghost - 确认docker的执行权限:
ls -l /var/run/docker.sock 有docker组
- 检查用户权限:
- 直接执行:
宿主机自动更新(容器不常驻,no模式)
- 【每日续期】同时也是验证cron定时服务
执行crontab -e 写入(Crontab 中,前五个参数:分钟、小时、日期、月份、星期)
# 每天早上 8 点 2分 自动续期 SSL 证书,并重启 Nginx 容器加载新证书 02 08 * * * 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>&1- cron执行日志:
cat /home/ghost/cron_certbot.log
- cron执行日志:
- 依赖定时任务服务
- cron任务列表:
crontab -l - cron任务编辑:
crontab -e - cron服务状态:
systemctl status crond - cron服务启动:
sudo systemctl enable --now crond - cron服务重启:
systemctl restart crond
- cron任务列表:
- 【每2周续期】正式任务
crontab -e 写入
# 每2周的周日日凌晨 3 点自动续期 SSL 证书,并重启 Nginx 容器加载新证书 0 3 1-7,15-21 * 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>&1- cron执行日志:
cat /home/ghost/cron_certbot.log