SSL: автоматичне оновлення

Хостинг із DirectAdmin — сертифікат оновлюється сам

Задача cron раз на добу забирає свіжий сертифікат і ставить його в DirectAdmin через API за ключем входу, якому дозволено лише SSL. Пароль не потрібен.

Оновлюється сам

Підходить для хостингу з панеллю DirectAdmin: NIC.UA, Tucha та багато інших. Ознака DirectAdmin — адреса входу закінчується на :2222, у меню є Account Manager, Advanced Features, System Info & Files.

Як це працює: скрипт раз на добу забирає сертифікат за посиланням і, якщо він новий, передає його панелі разом із вашим ключем — так само, як ви вставили б його руками в SSL Certificates. До панелі він заходить не паролем, а окремим ключем входу (Login Key), якому дозволена лише одна дія — встановити сертифікат. Ваш пароль від панелі і від хостингу ми не просимо й не бачимо.

Що знадобиться

  • Посилання на сертифікат із кабінету: https://api.zrazu.com/ssl-pull/zsp_ВАШ_ТОКЕН.
  • Закритий ключ, з яким замовляли сертифікат. Якщо CSR створював кабінет ZRAZU — це файл, який ви тоді зберегли.
  • Розділ Cron Jobs у панелі (є на більшості тарифів) або будь-який сервер Linux із curl і openssl.
  • 15 хвилин.

Крок 1. Перше встановлення (якщо сертифікат ще не стоїть)

У Account Manager → SSL Certificates оберіть Paste a pre-generated certificate and key, вставте в одне поле спершу ключ, під ним — сертифікат, збережіть. Потім Click Here to paste a CA Root Certificate, вставте ланцюжок (chain.pem з картки сертифіката), позначте Use a CA Cert і збережіть. Подробиці — у заміні сертифіката в панелі вручну.

Крок 2. Ключ входу лише для SSL

Account Manager → Login Keys → Create Key (у старих темах — Login Keys на головній):

  • Key Name — zrazu-ssl;
  • Key Value — натисніть Random і скопіюйте значення: його покажуть лише раз;
  • Expires On — Never (ключ потрібен щодня);
  • Commands — позначте лише CMD_API_SSL; без цього ключ відкриває всю панель;
  • Allowed IPs — IP, з якого запускатиметься скрипт. Якщо це cron самого хостингу — IP сервера (System Info & Files → System Information). Поле порожнє — ключ діє з будь-якої адреси;
  • Current Password — ваш пароль від панелі, щоб підтвердити створення.

Якщо пункту Login Keys немає — хостинг вимкнув цю можливість. Тоді лишається ручна заміна, ми нагадаємо про неї заздалегідь.

Крок 3. Файли в домашньому каталозі

У System Info & Files → File Manager створіть у домашньому каталозі (над domains і public_html) папку .zrazu і в ній три файли:

  • key.pem — закритий ключ разом із рядками -----BEGIN … PRIVATE KEY----- і -----END … PRIVATE KEY-----;
  • login — один рядок у лапках: ім'я користувача панелі, двокрапка, значення ключа входу:
user = "ІМ'Я_КОРИСТУВАЧА:ЗНАЧЕННЯ_КЛЮЧА"
  • zrazu-ssl.sh — скрипт нижче. Змініть у ньому лише рядок PANEL — адреса, за якою ви заходите в панель, з :2222, без шляху.

Усім трьом файлам поставте права 600 (Permissions у File Manager): читати їх може лише ваш обліковий запис.

#!/bin/sh
# ZRAZU: оновлення SSL-сертифіката в DirectAdmin за особистим посиланням. Запускається cron раз на добу.
# Ключ лишається у вас; у панель сертифікат іде, лише якщо він підходить до ключа.
set -eu
PATH=/usr/local/bin:/usr/bin:/bin
PULL="https://api.zrazu.com/ssl-pull/zsp_ВАШ_ТОКЕН"
DOMAIN="example.com"
PANEL="https://server.example.com:2222"
DIR="$HOME/.zrazu"
KEY="$DIR/key.pem"
# Ім'я і ключ входу — у файлі, а не в рядку запуску: так їх не видно іншим користувачам сервера.
LOGIN="$DIR/login"

umask 077
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
TAG=""
[ -f "$DIR/$DOMAIN.etag" ] && TAG=$(cat "$DIR/$DOMAIN.etag")
CODE=$(curl -fsS --retry 3 --max-time 60 -o "$WORK/full.pem" -D "$WORK/hdr" -w '%{http_code}' -H "If-None-Match: $TAG" "$PULL/fullchain.pem")
if [ "$CODE" = "304" ]; then echo "ZRAZU: сертифікат не змінився"; exit 0; fi
grep -q "BEGIN CERTIFICATE" "$WORK/full.pem" || { echo "ZRAZU: за посиланням не сертифікат" >&2; exit 1; }
# Перший сертифікат у файлі — сайту, решта — ланцюжок.
awk -v d="$WORK" '/BEGIN CERTIFICATE/{n++} n==1{print > (d "/cert.pem")} n>1{print > (d "/chain.pem")}' "$WORK/full.pem"
if [ "$(openssl x509 -in "$WORK/cert.pem" -noout -pubkey | openssl sha256)" != "$(openssl pkey -in "$KEY" -pubout | openssl sha256)" ]; then
  echo "ZRAZU: сертифікат випущено на інший ключ — нічого не міняю, покладіть новий ключ у $KEY" >&2
  exit 1
fi
openssl x509 -in "$WORK/cert.pem" -noout -checkend 0 >/dev/null || { echo "ZRAZU: сертифікат уже не діє" >&2; exit 1; }
# Панель приймає ключ і сертифікат одним полем: спершу ключ, під ним сертифікат.
cat "$KEY" "$WORK/cert.pem" > "$WORK/paste.pem"
api() {
  OUT=$(curl -sS --max-time 60 -K "$LOGIN" "$PANEL/CMD_API_SSL" -d "domain=$DOMAIN" -d action=save "$@") || true
  case "$OUT" in
    error=0*) ;;
    *) echo "ZRAZU: панель не прийняла: $(printf '%s' "$OUT" | head -c 300)" >&2; exit 1 ;;
  esac
}
api -d type=paste -d request=no --data-urlencode "certificate@$WORK/paste.pem"
if [ -s "$WORK/chain.pem" ]; then
  api -d type=cacert -d active=yes --data-urlencode "cacert@$WORK/chain.pem"
fi
# Метка — лише після того, як панель прийняла: не вдалося — наступний запуск спробує ще раз.
sed -n 's/^[Ee][Tt][Aa][Gg]: *//p' "$WORK/hdr" | tr -d '\r' > "$DIR/$DOMAIN.etag"
echo "ZRAZU: новий сертифікат встановлено, діє до $(openssl x509 -in "$WORK/cert.pem" -noout -enddate | cut -d= -f2)"

Скрипт нічого не міняє, якщо сертифікат не змінився, якщо за посиланням не сертифікат, якщо сертифікат не підходить до вашого ключа чи вже не діє. Панель відповідає error=0, коли прийняла сертифікат; будь-яка інша відповідь — помилка, і наступного дня скрипт спробує ще раз.

Крок 4. Розклад

Advanced Features → Cron Jobs → Create Cron Job: Minute 17, Hour 4, решта полів — *, команда:

/bin/sh $HOME/.zrazu/zrazu-ssl.sh >> $HOME/.zrazu/log.txt 2>&1

Хвилину можна взяти будь-яку — краще не рівно 00. Щоб перевірити одразу, тимчасово поставте час на дві хвилини вперед, а після запуску відкрийте .zrazu/log.txt: має бути «новий сертифікат встановлено».

Свій сервер Linux замість cron хостингу — той самий скрипт із HOME на свій каталог, рядок crontab -e: 17 4 * * * /bin/sh $HOME/.zrazu/zrazu-ssl.sh >> $HOME/.zrazu/log.txt 2>&1, а в Allowed IPs ключа — IP цього сервера.

Перевірка

Відкрийте https://zrazu.com/tools/ssl/example.com/ — має бути сертифікат ZRAZU з новою датою закінчення.

Щоб хостинг не замінив наш сертифікат

Якщо для домену увімкнено безкоштовний сертифікат (Free & automatic certificate from Let's Encrypt у SSL Certificates), панель сама поновлюватиме його і може замінити наш. Скрипт ставить сертифікат як вставлений вручну, і панель перестає поновлювати безкоштовний; перевірте після першого запуску, що в SSL Certificates обрано вставлений сертифікат.

Якщо не вийшло

Це нова інструкція: на живій панелі ми її ще не перевірили. Не спрацювало — напишіть нам у кабінеті (Звернення) чи на пошту з текстом із .zrazu/log.txt, виправимо інструкцію того ж дня.

  • «панель не прийняла» і в відповіді HTML зі словами Cannot Execute Your Request — ключ входу не має права на CMD_API_SSL або запуск іде з IP поза Allowed IPs. Перевірте крок 2.
  • error=1 і text=… — панель пояснила причину в text: найчастіше домен записано не так, як у панелі (без *. і без www).
  • curl: (60) чи SSL certificate problem — у PANEL адреса, на яку в панелі інший сертифікат. Візьміть адресу точно з рядка браузера, коли заходите в панель.
  • openssl: not found — на цьому хостингу немає openssl; запускайте скрипт зі свого сервера Linux.
  • curl: (22) … 404 — посилання вимкнене чи замінене: створіть нове в картці сертифіката і замініть рядок PULL.

Ця сторінка в Markdown