HTTPS для Nginx через LE

23 декабря 2019

Краткая памятка по настройке HTTPS для Nginx через LetsEncrypt

Сначала несколько общеизвестных фактов:

  • Сервис LetsEncrypt бесплатно предоставляет всем желающим заверенные SSL-сертификаты для доменных имён в публичных DNS-зонах.
  • Общение с сервисом производится только через API с помощью клиентских утилит, веб-интерфейса у него нет.
  • Выдавая сертификат на доменное имя, сервис требует от заявителя подтвердить, что он действительно является владельцем данного имени.
  • Подтверждение возможно одним из двух способов: через HTTP (по умолчанию) или через DNS.

Что требуется для подтверждения через HTTP?

  • Клиентская утилита обязана запускаться на том сервере, в IP-адрес которого распознаётся заверяемое доменное имя.
  • IP-адрес обязан быть публичным.
  • На порту 80 должен быть запущен Веб-сервер.
  • Веб-серверу требуется небольшая дополнительная настройка, чтобы правильно отвечать на проверочные запросы LetsEncrypt.

Почему в качестве клиентской утилиты мы выбрали dehydrated?

  • Потому что это один файл на bash с минимумом зависимостей (openssl и curl).
  • Потому что его пакет есть в стандартных репозитариях большиства дистрибутивов.
  • Потому что у него простая ручная установка в тех дистрибутивах, в которых готовый пакет отсутствует (например, в Ubuntu 16.04) или устарел.

Ручная установка (если нет готового пакета):

  • Скачиваем сценарий и делаем исполняемым:
  • cd /usr/bin
    wget https://raw.githubusercontent.com/lukas2511/dehydrated/master/dehydrated
    chmod +x dehydrated
  • Создаём каталоги:
  • mkdir /etc/dehydrated /var/lib/dehydrated
  • Создаём файл настроек /etc/dehydrated/config:
  • BASEDIR=/var/lib/dehydrated
    WELLKNOWN="${BASEDIR}/acme-challenges"
    DOMAINS_TXT="/etc/dehydrated/domains.txt"

Создаём ключи и получаем сертификаты:

  • Сначала создаём учётную запись в LetsEncrypt:
  • dehydrated --register --accept-terms
  • Добавляем имена в файл /etc/dehydrated/domains.txt (одна строка = имена одного сайта):
  • xx.ru www.xx.ru
    yy.ru www.yy.ru
  • Создаём /etc/nginx/sites-enabled/xx.ru.conf:
  • server {
        server_name xx.ru www.xx.ru;
        location ^~ /.well-known/acme-challenge {
            alias /var/lib/dehydrated/acme-challenges;
        }
        location / {
            return 301 https://$host$request_uri;
        }
  • Применяем новые настройки:
  • nginx -t
    nginx -s reload
  • И вызываем LetsEncrypt:
  • dehydrated -c
  • Если dehydrated отработает без ошибки, в /var/lib/dehydrated/certs появятся ключи и сертификаты.

Теперь включаем HTTPS:

  • Добавляем в /etc/nginx/sites-enabled/xx.ru.conf:
  • server {
          listen 443 ssl;
          server_name xx.ru www.xx.ru;
    
          ssl_certificate     /var/lib/dehydrated/certs/xx.ru/fullchain.pem;
          ssl_certificate_key /var/lib/dehydrated/certs/xx.ru/privkey.pem;
    }
  • И применяем новые настройки:
  • nginx -s reload

Настраиваем автопродление:

  • Сертификаты выдаются на 90 суток.
  • "dehydrated -c" без ключа "--force" не пытается продлевать сертификат, если он выдан менее 80 суток назад.
  • Поэтому оптимально вызывать продление раз в неделю — т.е. с минимумом неудачных попыток, но с гарантированным попаданием в заключительный 10-дневный интервал.
  • Для этого создаём файл /etc/cron.weekly/Dehydrated (и делаем его исполняемым через "chmod +x"):
  • #!/bin/sh
    
    dehydrated -c -g
  • Обратите внимание: при вызове через "cron" мы используем дополнительный ключ "-g", чтобы в случае ошибки dehydrated не прекратил работу, а продолжил обрабатывать следующие сертификаты.
  • Дополнительно создаём /etc/dehydrated/hook.sh (и тоже делаем исполняемым через "chmod +x"), который вызывается из основного сценария на разных стадиях выполнения. В нашем случае он будет простейшим:
  • #!/bin/sh
    
    test "$1" = "deploy_cert" || exit 0
    
    nginx -s reload
  • Проверяем, что /etc/dehydrated/config или /etc/dehydrated/conf.d/*.sh содержит директиву "HOOK=/etc/dehydrated/hook.sh" — в некоторых дистрибутивах она отсутствует!

Как и зачем использовать подтверждение через DNS вместо HTTP?

  • Сайт или сервис может быть недоступен из внешнего мира (находиться в офисной локальной сети, приватном облаке и т.д), поэтому LetsEncrypt не сумеет обратиться к нему извне, чтобы проверить владельца.
  • Либо по каким-то причинам мы вынуждены запускать клиентскую утилиту с другого компьютера.
  • В этом случае LetsEncrypt позволяет подтверждать владение доменом через специальные DNS-записи.
  • Для этого dehydrated должен запускаться с дополнительным ключом "-t dns-01".
  • Сценарий hook.sh становится примерно таким:
  • #!/bin/sh
    
    case "$1" in
      "deploy_challenge")  printf "Please add to DNS:\n_acme-challenge.%s. %d in TXT \"%s\"\n" "${2}" "${TTL}" "${4}"
                           read -p "Configure, then press Enter..." x  ;;
    
      "clean_challenge" )  printf "Please delete from DNS:\n_acme-challenge.%s. %d in TXT \"%s\"\n" "${2}" "${TTL}" "${4}" ;;
    
      "deploy_cert"     )  ;; # optional: /path/to/deploy_cert.sh "$@" ;;
    esac
  • Документация к Dehydrated содержит примеры автоматического создания-удаления DNS-записей через API различных DNS-провайдеров — Cloudflare, GoDaddy и т.д.


← Назад в Блог

Подпишитесь на новые статьи: