Получаем wildcard сертификат letsencrypt с помощью acme.sh

e68f1f2099b83e2a312bf1e9d7fe3355

Привет. Указанные ниже скрипты работают на виртуалке, которая занимается получением сертификатов. Потом на эту виртуалку приходит ansible по крону, забирает сертификаты и раскатывает их по всем остальным серверам и виртуалкам, где оно нужно.

Настраиваем cloudflare

На cloudflare делаешь аккаунт. Здесь всё просто и без подсказок справишься.

На втором этапе необходимо определить, DNS обслуживание домена будет происходить на cloudflare или же на другом ресурсе.

Если на cloudflare, то переносишь туда доменную зону, к примеру, pasha.com.
Если нет, то на cloudflare заводишь какой-либо «технический» домен, через который будешь получать и обновлять wildcard сертификаты для всех остальных доменов, например, pasha-on-cf.com

На cloudflare делаешь Global API KEY в My profile → API Tokens. Скорее всего можно через API Tokens, но я не пробовал, нужно проверять, какие права выдавать такому токену и тестировать.

Настраиваем DNS записи в домене

Если идёшь по схеме pasha.com, то ничего больше не делаешь на этом этапе.

Если идёшь по схеме pasha-on-cf.com, то в редакторе твоего DNS хостера/сервера для домена pasha.com нужно добавить CNAME запись вида:

_acme-challenge.pasha.com. CNAME _acme-challenge.pasha-on-cf.com.

Устанавливаешь acme.sh

Я устанавливаю под root пользователем, все дальнейшие скрипты исходят из этого.
На данном этапе укажи свой email и выполняй.

curl https://get.acme.sh | sh -s email=me@pashasemail.hiscom

Создай bash скрипт с авторизационными данными

Все скрипты лежат у меня в /opt/acme/
Здесь указываешь email от cloudflare аккаунта и Global API KEY.

Файл назови acme.cf.creds.sh

#!/bin/bash

export CF_Key="TOKeN-from_CloudFlaRe"
export CF_Email="your@email.org

Теперь создаём bash скрипты для получения сертификата

Для домена pasha-on-cf.com предлагается такой скрипт acme.issue.pasha-on-cf.com.sh

  • Напомню, что этот домен обслуживается на cloudflare.

  • Имя домена скрипт берёт из названия скрипта. Вложенность домена не играет роли, можно получить wildcard сертификат и для домена 3 го уровня и дальше. Однако здесь стоит уточнить, что для домена 3 го уровня нужно прописывать дополнительную CNAME запись, например, _acme-challenge.3dlevel.pasha.com. CNAME _acme-challenge.pasha-on-cf.com..

  • Получать сертификат можно у letsencrypt или zerossl или у других. Просто поменяй строчку 17. По последним тестам zerossl не выдаёт сертификаты для домена .ru

  • В строке 18 указано, куда класть готовые сертификаты. У меня они складываются в /opt/ssl/ и права меняются (строка 23) на того пользователя, который приходит ансиблом за этими сертификатами.

  • В приведённом ниже скрипте указано /etc/ssl/private/ — стандартизированное для меня расположение на всех серверах и виртуалках, куда обращаются nginx, proftpd и прочие апачи. И владелец с группой меняется на www-data из предположения, что скрипт будет работать на том же вебсервере, где и располагается сам nginx.

  • Почему файлы сертификата имеют названия domain.crt и domain.crt.key? — было испытано, что haproxy в таком наименовании поглощает сертификаты без каких-либо вопросов и дополнительных настроек, просто указываешь haproxy, где смотреть и он подтягивает все сертификаты, которые там есть.

#!/bin/bash
set -e

THIS=`readlink -f "${BASH_SOURCE[0]}"`
DIR=`dirname "${THIS}"`
pushd $DIR > /dev/null

TMP1="${THIS%.*}"
TMP2="${TMP1#*.}"
domain="${TMP2#*.}"
echo $domain;

date=`/bin/date +%Y%m%d.%H%M%S`
if [[ ! -f "acme.issue.$domain.done" ]]; then
  . ./acme.cf.creds.sh
  pushd /root/.acme.sh > /dev/null
  ./acme.sh --issue -d $domain -d '*.'$domain --dns dns_cf --server letsencrypt \
   --key-file /etc/ssl/private/$domain.crt.key --fullchain-file /etc/ssl/private/$domain.crt --keylength 4096
#   --force
#  --debug
  popd > /dev/null
  echo $date > acme.issue.$domain.done
  chown www-data. /etc/ssl/private/$domain.cr*
fi

popd > /dev/null

Для домена pasha.com предлагается такой скрипт acme.issue.pasha.com.sh

  • Напомню, что DNS этого домена обслуживается где-то ещё, а не на cloudflare.

  • И сертификат для домена pasha.com получается через «технический» домен pasha-on-cf.com.

  • Скрипт будет называться acme.issue.pasha.com.sh со следующим содержимым.

  • Отличие от предыдущего скрипта ищи в строке 17 в параметре --challenge-alias pasha-on-cf.com, именно для этого в самом начале ты создавал запись CNAME.

  • В строке 18 можешь указать длину ключа не 4096, а 2048, как вариант.

  • При успешном завершении скрипт создаёт флаг вида acme.issue.domain.done, который указывает, что сертификат успешно получен и не даёт скрипту исполняться повторно.

#!/bin/bash
set -e

THIS=`readlink -f "${BASH_SOURCE[0]}"`
DIR=`dirname "${THIS}"`
pushd $DIR > /dev/null

TMP1="${THIS%.*}"
TMP2="${TMP1#*.}"
domain="${TMP2#*.}"
echo $domain;

date=`/bin/date +%Y%m%d.%H%M%S`
if [[ ! -f "acme.issue.$domain.done" ]]; then
  . ./acme.cf.creds.sh
  pushd /root/.acme.sh > /dev/null
  ./acme.sh --issue -d $domain -d '*.'$domain --dns dns_cf --challenge-alias pasha-on-cf.com --server letsencrypt \
   --key-file /etc/ssl/private/$domain.crt.key --fullchain-file /etc/ssl/private/$domain.crt --keylength 4096
#  --force
#  --debug
  popd > /dev/null
  echo $date > acme.issue.$domain.done
  chown www-data. /etc/ssl/private/$domain.cr*
fi

popd > /dev/null

Получение сертификата

Теперь запускай один из скриптов, в названии которого ты указал свой домен, например:
acme.issue.mx.kamuzon.tech.sh, этот скрипт получит сертификаты для домена mx.kamuzon.tech и доменов *.mx.kamuzon.tech.

Если всё случилось, то последние строки должны быть такими:

[Fri Sep 20 12:53:08 UTC 2024] Cert success.
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
[Fri Sep 20 12:53:08 UTC 2024] Your cert is in: /root/.acme.sh/mx.kamuzon.tech/mx.kamuzon.tech.cer
[Fri Sep 20 12:53:08 UTC 2024] Your cert key is in: /root/.acme.sh/mx.kamuzon.tech/mx.kamuzon.tech.key
[Fri Sep 20 12:53:08 UTC 2024] The intermediate CA cert is in: /root/.acme.sh/mx.kamuzon.tech/ca.cer
[Fri Sep 20 12:53:08 UTC 2024] And the full chain certs is there: /root/.acme.sh/mx.kamuzon.tech/fullchain.cer
[Fri Sep 20 12:53:08 UTC 2024] Installing key to: /opt/ssl/mx.kamuzon.tech.crt.key
[Fri Sep 20 12:53:08 UTC 2024] Installing full chain to: /opt/ssl/mx.kamuzon.tech.crt

Если сертификат успешно получен, то можно настроить его автоматическое продление.

Обновление сертификата

В crontab -e добавь строку

5 3 */5 * * root "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

Или в /etc/cron.d/ положи файл aсme с содержимым:

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

5 3 */5 * * root "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

  • Обновление сертификатов будет происходить раз в 5 суток.

  • Чаще на мой взгляд не имеет смысла, чтобы не создавать лишнюю нагрузку на сервера letsencypt, а то им скоро придётся апгрейдиться на процессоры AMD SUPER EPIC.

  • Да и своему серверу какой смысл каждый день проверять, не протух ли сертификат. С учётом того, что новый сертификат выдаётся за дней 15–20 до истекания текущего.

© Habrahabr.ru