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

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

URL: https://zrazu.com/docs/ssl-auto-directadmin/

Підходить для хостингу з панеллю 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** і збережіть. Подробиці — у [заміні сертифіката в панелі вручну](https://zrazu.com/docs/ssl-auto-panels-manual.md).

## Крок 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** немає — хостинг вимкнув цю можливість. Тоді лишається [ручна заміна](https://zrazu.com/docs/ssl-auto-panels-manual.md), ми нагадаємо про неї заздалегідь.

## Крок 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): читати їх може лише ваш обліковий запис.

```sh file=zrazu-directadmin.sh
#!/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`, решта полів — `*`, команда:

```sh
/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/](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`.
