Certbot https SSL证书维护

用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定时任务调用

第一步:配置cerbot容器

services:
  certbot:
    container_name: "certbot"
    image: certbot/certbot:v3.1.0
    restart: "no"  # 需要长期挂着用unless-stopped,2周起来一次更新证书则用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
    # 核心修改:启动后执行 sleep infinity 保持容器运行
    # entrypoint: /bin/sh -c "apk add --no-cache py3-requests curl && sleep infinity"
    # 关键修改:使用 certonly 命令 + dns-01 挑战 + 手动钩子
    entrypoint: /bin/sh -c "apk add --no-cache py3-requests > /dev/null && certbot renew"
    deploy:
      resources:
        limits:
          memory: 32M
networks:
  ghost_net:
    external: true

给容器添加py脚本

  • certbot容器升级
    • pip工具升级:docker exec -it certbot pip install --upgrade certbot
    • 容器升级:修改docker-compose.yml里的certbot版本号,down容器,再up -d\
  • name域名脚本
    • 拉取脚本(宿主机):sudo git clone --depth 1 https://github.com/laonan/certbot-dns-name-com.git data/scripts/certbot-dns-name-com
    • 加权限(宿主机):sudo chmod +x data/scripts/certbot-dns-namecom.py
    • 脚本已通过容器的docker-compose.yml映射进容器了
  • name域名token配置

    [ghost@trilium20251227 certbot]$ cat data/scripts/certbot-dns-name-com/config.template.json
    {
        "namecom": {
          "username": "yourname",
          "token": "abcde"
        },
        "waitsec": 30
    }
    • name token配置文件:vi data/config/certbot-dns-namecom.config.json
    • 配置文件权限:sudo chmod 600 data/config/certbot-dns-namecom.config.json
    • 配置文件已通过容器的docker-compose.yml映射进容器了
    • 将服务器ip放入name.com的api 白名单

测试

  • name api 可用:python3 -c "import requests; r = requests.get('https://api.name.com/v4/domains/YOUR_DOMAIN', auth=('YOUR_USERNAME', 'YOUR_TOKEN')); print(r.status_code); print(r.json())"
  • 目前docker-compose.yml的效果是启动即renew更新证书,运行结束容器退出。
  • 申请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
    • 申请泛域名
  • 证书维护
    • 查看证书: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

手动操作证书

  • 【查看证书】
    • 因为容器改造为启动就renew,所以无法手动查看整数,renew日志会告知最新有效期
  • 【手动续期】同时也是权限验证
    • 直接执行:{ 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
    • 依赖ghost用户的docker权限
      • 检查用户权限:id ghost
      • 增加组权限:sudo usermod -aG docker ghost
      • 确认docker的执行权限:ls -l /var/run/docker.sock 有docker组

宿主机自动更新

  • 【每日续期】同时也是验证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任务列表:crontab -l
      • cron任务编辑:crontab -e
      • cron服务状态:systemctl status crond
      • cron服务启动:sudo systemctl enable --now crond
      • cron服务重启:systemctl restart crond
  • 【每2周续期】正式任务
    • crontab -e 写入

      # 每周日日凌晨 3 点自动续期 SSL 证书,并重启 Nginx 容器加载新证书
      0 3 * * 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