smart-chatbot-api / scripts /init-letsencrypt.sh
GitHub Actions
Deploy from GitHub Actions (2026-06-03 15:30 UTC)
3a0095b
Raw
History Blame Contribute Delete
4.02 kB
#!/bin/bash
# init-letsencrypt.sh
# Bootstrap SSL certificate for first deployment.
# Run ONCE. After this, certbot auto-renews every 12 hours.
set -e
ENV_FILE=".env.production"
COMPOSE_FILE="docker-compose.prod.yml"
COMPOSE="docker compose --env-file $ENV_FILE -f $COMPOSE_FILE"
# ---------------------------------------------------------------------------
# Read config from .env.production
# ---------------------------------------------------------------------------
DOMAIN=$(grep '^NGINX_DOMAIN=' "$ENV_FILE" | cut -d= -f2 | tr -d ' ')
EMAIL=$(grep '^CERTBOT_EMAIL=' "$ENV_FILE" | cut -d= -f2 | tr -d ' ')
if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then
echo "ERROR: NGINX_DOMAIN and CERTBOT_EMAIL must be set in $ENV_FILE"
exit 1
fi
echo "==> Domain : $DOMAIN"
echo "==> Email : $EMAIL"
echo ""
# ---------------------------------------------------------------------------
# Step 0: Skip bootstrap if a real cert already exists
# ---------------------------------------------------------------------------
echo "==> Checking for existing certificates..."
if $COMPOSE run --rm --entrypoint sh certbot \
-c "test -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem"; then
echo "==> Certificates already exist. Starting nginx..."
$COMPOSE up -d --wait nginx
echo "==> Done. nginx is running with the existing certificate."
exit 0
fi
echo "==> No certificates found. Starting bootstrap..."
echo ""
# ---------------------------------------------------------------------------
# Step 1: Create a temporary self-signed certificate so nginx can start.
# nginx refuses to start if the ssl_certificate path does not exist.
# ---------------------------------------------------------------------------
echo "==> [1/4] Creating temporary self-signed certificate..."
$COMPOSE run --rm --entrypoint sh certbot -c \
"mkdir -p /etc/letsencrypt/live/$DOMAIN && \
openssl req -x509 -nodes -newkey rsa:4096 -days 1 \
-keyout /etc/letsencrypt/live/$DOMAIN/privkey.pem \
-out /etc/letsencrypt/live/$DOMAIN/fullchain.pem \
-subj /CN=localhost \
-quiet"
# Verify the cert was actually created before continuing
if ! $COMPOSE run --rm --entrypoint sh certbot \
-c "test -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem"; then
echo "ERROR: Failed to create temporary certificate. Check the certbot image."
exit 1
fi
echo "==> Temporary certificate created."
# ---------------------------------------------------------------------------
# Step 2: Start nginx (and all backend dependencies).
# --wait blocks until every health check passes.
# ---------------------------------------------------------------------------
echo "==> [2/4] Starting nginx and backend services..."
$COMPOSE up -d --wait nginx
echo "==> nginx is up."
# ---------------------------------------------------------------------------
# Step 3: Request the real certificate from Let's Encrypt.
# The certbot image uses certbot as its entrypoint — pass certonly
# and flags directly as the command.
# ---------------------------------------------------------------------------
echo "==> [3/4] Requesting SSL certificate from Let's Encrypt..."
$COMPOSE run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
-d "$DOMAIN"
# ---------------------------------------------------------------------------
# Step 4: Reload nginx so it picks up the real certificate.
# ---------------------------------------------------------------------------
echo "==> [4/4] Reloading nginx with the real certificate..."
$COMPOSE exec nginx nginx -s reload
echo ""
echo "===================================================================="
echo " SSL certificate obtained successfully!"
echo " Site is live at: https://$DOMAIN"
echo ""
echo " Next step: run 'make prod-up' to start all remaining services."
echo "===================================================================="