DealDocumentScreening/deploy/nginx/certbot-init.sh

85 lines
2.9 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# certbot-init.sh — obtain the first Let's Encrypt certificate for the
# «Контракт-чек» edge proxy and (re)start nginx.
#
# Bootstrap (first run, no certificate yet):
# nginx CANNOT start before a certificate exists — the rendered config
# references /etc/letsencrypt/live/<domain>/*.pem and nginx exits if those
# files are missing. So the first certificate is obtained in --standalone
# mode: certbot binds port 80 itself (nginx is down at this point, so the
# port is free). After issuance the script starts nginx; the certbot renew
# sidecar then uses the webroot plugin against the running nginx.
#
# Subsequent runs (certificate already exists): webroot renew via the running
# nginx + `nginx -s reload`.
#
# Usage:
# chmod +x deploy/nginx/certbot-init.sh
# ./deploy/nginx/certbot-init.sh your-domain.example.com admin@example.com
#
# Requirements:
# - DNS A-record for the domain points at this server
# - NGINX_SERVER_NAME=<same domain> is set in .env
# - the `services` profile is up (api healthy) — nginx depends on it
DOMAIN="${1:-}"
EMAIL="${2:-}"
if [[ -z "$DOMAIN" || -z "$EMAIL" ]]; then
echo "Usage: $0 <domain> <email>"
exit 1
fi
if [[ -f .env ]] && ! grep -qE "^NGINX_SERVER_NAME=${DOMAIN}\s*$" .env; then
echo "ERROR: NGINX_SERVER_NAME in .env must equal ${DOMAIN}." >&2
echo " nginx renders server_name and the certificate path from it." >&2
echo " Add/fix: NGINX_SERVER_NAME=${DOMAIN}" >&2
exit 1
fi
# nginx depends on api (service_healthy), and api is gated behind the
# `services` profile — both profiles must be enabled for compose to
# resolve the dependency graph.
DC=(docker compose --profile services --profile edge)
CERTBOT_WEBROOT=/var/www/certbot
LE_DIR=/etc/letsencrypt
cert_exists() {
"${DC[@]}" run --rm --entrypoint sh certbot \
-c "test -f ${LE_DIR}/live/${DOMAIN}/fullchain.pem" >/dev/null 2>&1
}
if cert_exists; then
echo ">>> Certificate already exists — renewing via webroot (nginx serves the challenge)."
"${DC[@]}" run --rm --entrypoint "certbot certonly \
--webroot \
--webroot-path ${CERTBOT_WEBROOT} \
--agree-tos \
--no-eff-email \
--email ${EMAIL} \
-d ${DOMAIN} \
--non-interactive \
--keep-until-expiring" certbot
else
echo ">>> No certificate yet — obtaining via standalone on port 80."
# nginx cannot boot without a certificate (see header), so port 80 is free.
"${DC[@]}" stop nginx >/dev/null 2>&1 || true
"${DC[@]}" run --rm -p 80:80 --entrypoint "certbot certonly \
--standalone \
--agree-tos \
--no-eff-email \
--email ${EMAIL} \
-d ${DOMAIN} \
--non-interactive" certbot
fi
# Start (or re-create) nginx + the certbot renew sidecar.
"${DC[@]}" up -d nginx certbot
# Reload in case nginx was already running with an old certificate.
"${DC[@]}" exec nginx nginx -s reload || true
echo "Certificate issued for ${DOMAIN}. Nginx (re)started."