# Сервер Linux — nginx, Apache, Caddy, HAProxy, Docker

> Скрипт для nginx, Apache, Caddy, HAProxy и Docker раз в сутки забирает свежий сертификат, сверяет его с вашим ключом и перезапускает сервер без простоя.

URL: https://zrazu.com/ru/docs/ssl-auto-linux/

Подходит, если у вас есть доступ к серверу по SSH и права root (VPS, выделенный сервер, свой компьютер в стойке). Нужны `curl` и `openssl` — они есть почти в каждом Linux.

## Что понадобится

- Ссылка на сертификат из кабинета: `https://api.zrazu.com/ssl-pull/zsp_ВАШ_ТОКЕН`.
- Закрытый ключ, с которым заказывали сертификат (файл `key.pem` или похожий). Если CSR создавал кабинет ZRAZU — это файл, который вы тогда сохранили.
- 10 минут.

## Шаг 1. Положите ключ на сервер

```sh
sudo mkdir -p /etc/ssl/zrazu/example.com
sudo chmod 700 /etc/ssl/zrazu/example.com
sudo nano /etc/ssl/zrazu/example.com/key.pem
sudo chmod 600 /etc/ssl/zrazu/example.com/key.pem
```

В `nano` вставьте весь текст ключа вместе со строками `-----BEGIN … PRIVATE KEY-----` и `-----END … PRIVATE KEY-----`, сохраните (Ctrl+O, Enter) и выйдите (Ctrl+X). Ключ без пароля: если ваш ключ запаролен, снимите пароль командой `openssl pkey -in старый.key -out /etc/ssl/zrazu/example.com/key.pem`.

## Шаг 2. Скрипт обновления

Создайте файл `sudo nano /usr/local/bin/zrazu-ssl-example.com.sh`, вставьте текст ниже и измените только строку `RELOAD` под свой веб-сервер:

- nginx — `nginx -t && systemctl reload nginx` (так стоит);
- Apache (Debian, Ubuntu) — `apachectl configtest && systemctl reload apache2`; Apache (CentOS, Rocky, Alma) — `apachectl configtest && systemctl reload httpd`;
- Caddy — `systemctl reload caddy`;
- HAProxy — `systemctl reload haproxy` и `COMBINED=1` (HAProxy читает сертификат и ключ одним файлом `combined.pem`);
- nginx в Docker — `docker exec ИМЯ_КОНТЕЙНЕРА nginx -s reload` (каталог `/etc/ssl/zrazu` подключите в контейнер как том).

```sh file=zrazu-ssl-update.sh
#!/bin/sh
# ZRAZU: обновление SSL-сертификата по личной ссылке. Запускается cron раз в сутки.
set -eu
# cron даёт короткий PATH без /usr/sbin, а nginx и apachectl лежат именно там.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PULL="https://api.zrazu.com/ssl-pull/zsp_ВАШ_ТОКЕН"
DIR="/etc/ssl/zrazu/example.com"
KEY="$DIR/key.pem"
RELOAD="nginx -t && systemctl reload nginx"
COMBINED=0

umask 077
tmp=$(mktemp "$DIR/.new.XXXXXX")
trap 'rm -f "$tmp"' EXIT
curl -fsS --retry 3 --max-time 60 -o "$tmp" "$PULL/fullchain.pem"
grep -q "BEGIN CERTIFICATE" "$tmp" || { echo "ZRAZU: по ссылке не сертификат"; exit 1; }
if [ -f "$DIR/.applied" ] && cmp -s "$tmp" "$DIR/.applied"; then
  echo "ZRAZU: сертификат не изменился"
  exit 0
fi
cert_pub=$(openssl x509 -in "$tmp" -noout -pubkey | openssl sha256)
key_pub=$(openssl pkey -in "$KEY" -pubout | openssl sha256)
if [ "$cert_pub" != "$key_pub" ]; then
  echo "ZRAZU: сертификат выпущен на другой ключ — ничего не меняю, положите новый ключ в $KEY"
  exit 1
fi
openssl x509 -in "$tmp" -noout -checkend 0 >/dev/null || { echo "ZRAZU: сертификат уже не действует"; exit 1; }
chmod 644 "$tmp"
mv -f "$tmp" "$DIR/fullchain.pem"
if [ "$COMBINED" = 1 ]; then
  cat "$DIR/fullchain.pem" "$KEY" > "$DIR/combined.pem.new"
  mv -f "$DIR/combined.pem.new" "$DIR/combined.pem"
fi
sh -c "$RELOAD"
cp "$DIR/fullchain.pem" "$DIR/.applied"
echo "ZRAZU: новый сертификат установлен, действует до $(openssl x509 -in "$DIR/fullchain.pem" -noout -enddate | cut -d= -f2)"
```

Скрипт ничего не меняет, если веб-сервер уже работает с этим сертификатом, если файл по ссылке не сертификат, если сертификат не подходит к вашему ключу или уже не действует. Конфигурацию веб-сервера он проверяет перед перезапуском, так что сломанный конфиг сайт не уронит; а если перезапуск не удался, на следующий день скрипт попробует ещё раз.

Сделайте файл исполняемым и запустите один раз вручную:

```sh
sudo chmod 700 /usr/local/bin/zrazu-ssl-example.com.sh
sudo /usr/local/bin/zrazu-ssl-example.com.sh
```

Должно появиться «новый сертификат установлен» и файл `/etc/ssl/zrazu/example.com/fullchain.pem`.

## Шаг 3. Укажите файлы в веб-сервере (один раз)

nginx — в блоке `server` сайта:

```nginx
ssl_certificate     /etc/ssl/zrazu/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/zrazu/example.com/key.pem;
```

Apache 2.4.8 и новее — в `<VirtualHost *:443>`:

```apache
SSLCertificateFile    /etc/ssl/zrazu/example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/zrazu/example.com/key.pem
```

Caddy — в блоке сайта `tls /etc/ssl/zrazu/example.com/fullchain.pem /etc/ssl/zrazu/example.com/key.pem`. HAProxy — в `bind :443 ssl crt /etc/ssl/zrazu/example.com/combined.pem`.

Проверьте конфиг (`nginx -t` или `apachectl configtest`) и перезапустите веб-сервер.

## Шаг 4. Расписание

```sh
echo "17 4 * * * root /usr/local/bin/zrazu-ssl-example.com.sh >> /var/log/zrazu-ssl.log 2>&1" | sudo tee /etc/cron.d/zrazu-ssl-example.com
```

Скрипт будет запускаться каждый день в 04:17 по времени сервера. Минуту можно взять любую — лучше не ровно 00.

## Проверка

1. `sudo tail /var/log/zrazu-ssl.log` — завтра там появится «сертификат не изменился»: расписание работает.
2. Сайт отдаёт наш сертификат: `echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -enddate` или страница [https://zrazu.com/tools/ssl/example.com/](https://zrazu.com/tools/ssl/example.com/).
3. В кабинете, в карточке сертификата, видно, что сервер забрал действующий сертификат.

## Если не получилось

- `curl: (22) … 404` — ссылка отключена или заменена. В карточке сертификата создайте новую и замените строку `PULL` в скрипте.
- `curl: (22) … 429` — слишком много запросов (больше 60 в час). Раз в сутки — с большим запасом.
- «сертификат выпущен на другой ключ» — сертификат перевыпускали с новым ключом. Положите новый ключ в `key.pem` и запустите скрипт ещё раз.
- `nginx: [emerg]` после перезапуска — ошибка в конфигурации сайта, не в сертификате; старый сертификат остаётся в работе, пока ошибку не исправите.
