Сертификаты LetsEncrypt для Nginx используя Docker

Let’s Encrypt - сервис, который предоставляет бесплатные криптографические сертификаты для TLS шифрования и собственно поддержки HTTPS протокола. Данные сертификаты выдаются бесплатно, но дейтвительны 90 дней, после чего требуется заново их получить. Для получения сертификатов используя Docker первым делом нужно создать volumes, которые в последующем будут связаны с контейнером nginx.

$ docker volume create certs
$ docker volume create certs-data

В docker-compose файле свяжим их с nginx. Обязательно нужно указать, что данные volumes беруться извне, чтобы docker-compose не создал свои:

  nginx:
    image: nginx:latest
    restart: on-failure
    volumes:
      - ./docker/nginx/prod.conf:/etc/nginx/conf.d/default.conf
      - certs:/etc/letsencrypt
      - certs-data:/data/letsencrypt
    ports:
      - 80:80
      - 443:443
      
volumes:
  certs:
    external: true
  certs-data:
    external: true

В конфигурационном файле для nginx нужно прописать путь .well-known для проверки владения доменным именем (ACME challendge). Например конфигурация для моего сайта выглядит таким образом:

server {
    listen 80;
    server_name dikiigr.ru www.dikiigr.ru;;

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }

    location ^~ /.well-known {
        allow all;
        root  /data/letsencrypt/;
    }
}

Для получения сертификатов используется программа cerbot. Но прежде чем запустить его, нужно запусть контейнер с nginx, чтобы acme challendge прошел успешно.

$ docker-compose up

Теперь можно получать сертификаты.

$ docker run -it --rm \
      -v certs:/etc/letsencrypt \
      -v certs-data:/data/letsencrypt \
      deliverous/certbot \
      certonly \
      --webroot --webroot-path=/data/letsencrypt \
      -d dikiigr.ru -d www.dikiigr.ru

После успелного выполнения данной команды у нас сформируются приватный и открытый ключ. Для работы HTTPS ngix нужно указать пути к ним, для этого нужно добавить новую секцию в нашу конфигурацию:

server {
    listen 443 ssl;
    server_name dikiigr.ru www.dikiigr.ru;

    ssl_certificate           /etc/letsencrypt/live/dikiigr.ru/fullchain.pem;
    ssl_certificate_key       /etc/letsencrypt/live/dikiigr.ru/privkey.pem;
    ssl_trusted_certificate   /etc/letsencrypt/live/dikiigr.ru/chain.pem;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 127.0.0.1 8.8.8.8;
    
    # Редирект с www
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) { return 301 https://dikiigr.ru$request_uri; }

    # Ваша конфигурация ..
}

Для обновления сертификатов нужно выполнить команду:

$ docker run -t --rm \
      -v certs:/etc/letsencrypt \
      -v certs-data:/data/letsencrypt \
      deliverous/certbot \
      renew \
      --webroot --webroot-path=/data/letsencrypt

Не забудем перезапустить контейнер послав сигнал:

docker-compose kill -s SIGHUP nginx

Можно задать cronjon, чтобы каждые 60 дней сам обновлял сертификаты:

0 0 */30 * * docker run -t --rm -v certs:/etc/letsencrypt -v certs-data:/data/letsencrypt -v /var/log/letsencrypt:/var/log/letsencrypt deliverous/certbot renew --webroot --webroot-path=/data/letsencrypt && docker kill -s HUP nginx >/dev/null 2>&1

Настраивал на основе данной статьи.