如何使用 certbot 自动续订 TLS 证书?

How to do auto-renewal of TLS certificates with certbot?

提问人:AnjK 提问时间:3/15/2021 更新时间:12/10/2021 访问量:22274

问:

我有一个带有 Nginx docker 容器的应用程序,TLS 证书是在部署应用程序的主机(使用 Ubuntu 操作系统)中使用以下命令手动生成的:

certbot certonly --manual --manual-public-ip-logging-ok --preferred-challenges dns -d my.app.com

当证书过期时,我必须续订它们。

但是我不能为此目的使用以下命令,因为它会给出错误:certbot renew

$ sudo certbot renew

Failed to renew certificate my.app.com with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')

因此,我现在正在做的是再次创建证书(使用以前使用的相同命令)而不是更新它们。certbot certonly

如何使用命令修复错误?certbot renew

如何自动执行此设置?

Ubuntu SSL-Certificate CertBot 手动 自动续订

评论


答:

20赞 schrom 3/15/2021 #1

这是我的设置。它涉及 nginx 和 certbot 之间共享的 docker 卷中的 LE 密钥,以及 nginx 将续订请求代理给 certbot,因此您不必在 certbot 进行验证时停止 nginx。

nginx 设置

将 LE 验证代理到 certbot 后端

端口 80 上对 letsencrypt 验证的请求将转发到 certbot,其他任何内容都将重定向到 https。 (如果您想知道为什么我将代理传递后端定义为变量,请参阅此 SO 答案)

  server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    location /.well-known/acme-challenge {
      resolver 127.0.0.11 valid=30s;
      set $upstream letsencrypt;
      proxy_pass http://$upstream:80;
      proxy_set_header Host            $host;
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header X-Forwarded-Proto https;
    }

    location / {
      return 301 https://$host$request_uri;
    }
  }

SSL 设置

这里几乎是标准的东西:

  server {
    listen 443 ssl;
    server_name ${DOMAINNAME};

    ssl_certificate /etc/letsencrypt/live/${DOMAINNAME}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAINNAME}/privkey.pem;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2;
    ssl_ciphers 'EECDH+AESGCM: EDH+AESGCM:AES256+EECDH:AES256+EDH';
    ssl_prefer_server_ciphers on;

    ssl_session_cache shared:SSL:10m;
    ssl_dhparam dhparam.pem;

    ... your lcoation block goes here ...

}

docker-compose 魔术

certbot (英语)

有一个特殊的“docker-compose-LE.yml”来单次运行 certbot:

version: '3.4'

services:

  letsencrypt:
    image: certbot/certbot:latest
    command: sh -c "certbot certonly --standalone -d ${DOMAINNAME} --text --agree-tos --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --preferred-challenges=http"
    entrypoint: ""
    volumes:
      - "letsencrypt:/etc/letsencrypt"
    environment:
      - TERM=xterm

volumes:
  letsencrypt:
    name: letsencrypt_keys

通过运行“docker-compose -f docker-compose-LE.yml up”,您将创建并验证证书。您可以使用相同的命令来续订证书,certbot 就是这么聪明。您可以根据需要(每天)运行此命令,因为它只会在证书即将过期时续订您的证书。

在首次运行此命令之前,请参阅下面的“注意事项”。

nginx的

在 docker-compose.yml 中,从卷挂载证书。letsencrypt 已经创建了该卷,因此将其声明为外部卷。

services:
  nginx:
    image: nginx:1.18
    restart: always
    volumes:
      - letsencrypt:/etc/letsencrypt:ro

volumes:
  letsencrypt:
    external:
      name: letsencrypt_keys

警告

此方法在首次创建证书时会导致先有鸡先有蛋的问题:如果没有证书文件,nginx 将无法启动,也无法代理 LE 验证。没有 nginx 意味着没有证书,没有证书意味着没有 nginx。

为了解决这个问题,你必须在没有nginx的情况下进行certbot的第一次调用,并使用certbots内部http服务器公开。因此,首次运行 certbot 时,请将以下行添加到docker-compose-LE.yml:

  letsencrypt:
    ports:
      - "80:80"

证书续订

只需在每日 cronjob 中运行以下两个命令:

docker-compose -f docker-compose-LE.yml up

将检查证书并在到期后开始续订过程。现在正在运行的 nginx 会将证书验证代理给 certbot。

docker-compose exec nginx nginx -s reload

在 certbot 和 nginx 共享的 docker 卷中就地更新证书后,只需向 nginx 发送 SIGHUP,即可在不中断服务的情况下重新加载证书文件。

0赞 ech0r 12/10/2021 #2

我需要使用“外部”网络来允许两个docker-compose文件中的容器进行通信。谢谢你!

version: '3.4'
services:
  letsencrypt:
    container_name: "letsencrypt"
      #ports:
        #- "80:80"
    image: certbot/certbot:latest
    command: sh -c "certbot certonly --standalone --rsa-key-size 4096 --agree-tos --preferred-challenges http -d ${DOMAINNAME} -m ${CONTACT_EMAIL} -n"
    entrypoint: ""
    volumes:
      - "letsencrypt:/etc/letsencrypt"
    networks:
      - web_nw
networks:
  web_nw:
    external: true
volumes:
  letsencrypt:
    name: letsencrypt