#!/usr/bin/env bash # Однократная настройка nginx и HTTPS для kvarta.unuchak.com. Запускать локально из корня: # CERTBOT_EMAIL=you@example.com deploy/setup-nginx.sh # Хост: DEPLOY_HOST (по умолчанию root@185.5.249.52). Повторный запуск безопасен. # # На сервере чужие боевые сайты: при ошибке `nginx -t` наш симлинк убирается # и reload не делается — общий nginx не должен упасть из-за нашего конфига. set -euo pipefail DEPLOY_HOST="${DEPLOY_HOST:-root@185.5.249.52}" DOMAIN=kvarta.unuchak.com CONF_SRC="deploy/nginx/$DOMAIN.conf" AVAILABLE="/etc/nginx/sites-available/$DOMAIN" ENABLED="/etc/nginx/sites-enabled/$DOMAIN" SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=10 -o ControlMaster=auto -o "ControlPath=$HOME/.ssh/kvarta-nginx-%C" -o ControlPersist=60) STEP=0 step() { STEP=$((STEP + 1)); printf '\n\033[1m[%d] %s\033[0m\n' "$STEP" "$*"; } info() { printf ' %s\n' "$*"; } die() { printf '\033[31mОШИБКА: %s\033[0m\n' "$*" >&2; exit 1; } # shellcheck disable=SC2029 # команды для сервера собираются локально намеренно remote() { ssh "${SSH_OPTS[@]}" "$DEPLOY_HOST" "$@"; } cd "$(dirname "$0")/.." step "Проверка параметров" if [[ -z ${CERTBOT_EMAIL:-} ]]; then die "задайте CERTBOT_EMAIL — на него Let's Encrypt шлёт предупреждения об истечении сертификата: CERTBOT_EMAIL=you@example.com deploy/setup-nginx.sh" fi [[ $CERTBOT_EMAIL =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]] \ || die "CERTBOT_EMAIL не похож на email: $CERTBOT_EMAIL" [[ -f $CONF_SRC ]] || die "нет $CONF_SRC" info "хост $DEPLOY_HOST, домен $DOMAIN, email $CERTBOT_EMAIL" step "Проверка сервера" remote true || die "нет ssh-доступа к $DEPLOY_HOST" remote 'command -v nginx >/dev/null && command -v certbot >/dev/null' \ || die "на сервере нет nginx или certbot" # общий nginx должен быть исправен до нас — иначе мы не отличим свою ошибку от чужой remote 'nginx -t 2>&1' >/dev/null || die "nginx -t падает ещё до наших изменений — разберитесь вручную, скрипт ничего не трогал" step "Конфиг в $AVAILABLE" # если certbot уже дописал в конфиг 443-блок — не затираем его исходным 80-м if remote "grep -q 'managed by Certbot' $AVAILABLE 2>/dev/null"; then info "конфиг уже обработан certbot — оставляю как есть" else # прежняя версия нашего конфига — чтобы вернуть её, если новая не пройдёт nginx -t remote "[ ! -e $AVAILABLE ] || cp -a $AVAILABLE $AVAILABLE.bak" scp -q "${SSH_OPTS[@]}" "$CONF_SRC" "$DEPLOY_HOST:$AVAILABLE" info "скопирован" fi step "Симлинк в sites-enabled" created_link=0 if remote "[ -e $ENABLED ] || [ -L $ENABLED ]"; then info "уже есть — не трогаю" else remote "ln -s $AVAILABLE $ENABLED" created_link=1 info "создан $ENABLED" fi step "nginx -t" if ! remote 'nginx -t'; then if ((created_link)); then remote "rm -f $ENABLED" info "наш симлинк удалён" fi if remote "[ -e $AVAILABLE.bak ]"; then remote "mv -f $AVAILABLE.bak $AVAILABLE" info "восстановлена прежняя версия $AVAILABLE" fi die "конфиг не прошёл nginx -t — reload не выполнен" fi remote "rm -f $AVAILABLE.bak" step "systemctl reload nginx" remote 'systemctl reload nginx' step "Сертификат Let's Encrypt (certbot --nginx)" remote "certbot --nginx -d $DOMAIN --non-interactive --agree-tos --redirect -m '$CERTBOT_EMAIL'" step "Итоговая проверка" remote 'nginx -t' && remote "curl -fsS -o /dev/null -w 'https://$DOMAIN/ → %{http_code}\n' https://$DOMAIN/ || true" printf '\nГотово: https://%s\n' "$DOMAIN"