如何使用 certbot 自动更新 TLS 证书?

时间:2021-03-15 12:51:56

标签: ubuntu ssl-certificate certbot manual auto-renewing

我有一个带有 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 命令修复错误?

如何自动执行此设置?

1 个答案:

答案 0 :(得分:3)

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

nginx 设置

代理 LE 验证到 certbot 后端

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

  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 魔法

证书机器人

有一个特殊的“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 you@example.com --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 中从卷挂载证书。该卷已由 letencrypt 创建,因此将其声明为外部卷。

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"

证书更新

只需在每日定时任务中运行这两个命令:

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

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

docker-compose exec nginx nginx -s reload

一旦证书在 docker volume certbot 和 nginx 共享中就地更新,只需向 nginx 发送一个 SIGHUP,这样它就可以在不中断服务的情况下重新加载证书文件。