diff --git a/tools/ssl/setup_ssl.sh b/tools/ssl/setup_ssl.sh index e55e697..2110a66 100755 --- a/tools/ssl/setup_ssl.sh +++ b/tools/ssl/setup_ssl.sh @@ -2,6 +2,9 @@ # SSL Certificate Setup Script for All Mnemo Cards Domains # Usage: ./setup_ssl.sh +# +# This script uses nginx webroot mode for certificate issuance/renewal +# which doesn't require stopping nginx. set -e @@ -40,7 +43,7 @@ fi # Email for Let's Encrypt (can be overridden) LETSENCRYPT_EMAIL="${LETSENCRYPT_EMAIL:-admin@mnemo-cards.online}" -# Domains to set up certificates for +# Domains to set up certificates for (only mnemo-cards.online domains) DOMAINS=( "mnemo-cards.online" "api.mnemo-cards.online" @@ -49,66 +52,88 @@ DOMAINS=( "vscode.mnemo-cards.online" ) +# Webroot path for ACME challenge +WEBROOT_PATH="/var/www/html" + # Check if certbot is installed if ! command -v certbot &> /dev/null; then - print_status "Installing certbot..." + print_status "Installing certbot and nginx plugin..." apt update - apt install -y certbot + apt install -y certbot python3-certbot-nginx print_success "Certbot installed" fi -# Stop nginx temporarily for certificate issuance -print_warning "Stopping nginx for certificate issuance..." -systemctl stop nginx 2>/dev/null || true +# Ensure webroot directory exists +mkdir -p "$WEBROOT_PATH/.well-known/acme-challenge" +chmod -R 755 "$WEBROOT_PATH/.well-known" -# Get certificates for all domains +# Clean up old/invalid certificate for hosting domain (not our domain) +if [ -d "/etc/letsencrypt/live/5492281-cf88967.twc1.net" ]; then + print_warning "Removing old hosting certificate (5492281-cf88967.twc1.net)..." + certbot delete --cert-name 5492281-cf88967.twc1.net --non-interactive 2>/dev/null || true + rm -rf /etc/letsencrypt/live/5492281-cf88967.twc1.net 2>/dev/null || true + rm -rf /etc/letsencrypt/archive/5492281-cf88967.twc1.net 2>/dev/null || true + rm -f /etc/letsencrypt/renewal/5492281-cf88967.twc1.net.conf 2>/dev/null || true + print_success "Old hosting certificate removed" +fi + +# Get certificates for all domains using nginx plugin (no downtime) for domain in "${DOMAINS[@]}"; do - if [ -d "/etc/letsencrypt/live/$domain" ]; then + if [ -d "/etc/letsencrypt/live/$domain" ] && [ -f "/etc/letsencrypt/live/$domain/fullchain.pem" ]; then print_success "Certificate already exists for $domain" else print_status "Obtaining certificate for $domain..." - if certbot certonly --standalone -d "$domain" --non-interactive --agree-tos --email "$LETSENCRYPT_EMAIL"; then + # Use nginx plugin - it handles configuration automatically without stopping nginx + if certbot certonly --nginx -d "$domain" --non-interactive --agree-tos --email "$LETSENCRYPT_EMAIL"; then print_success "Certificate obtained for $domain" else - print_error "Failed to obtain certificate for $domain" + print_warning "Nginx plugin failed for $domain, trying standalone..." + # Fallback to standalone (requires stopping nginx briefly) + systemctl stop nginx 2>/dev/null || true + if certbot certonly --standalone -d "$domain" --non-interactive --agree-tos --email "$LETSENCRYPT_EMAIL"; then + print_success "Certificate obtained for $domain (standalone)" + else + print_error "Failed to obtain certificate for $domain" + fi + systemctl start nginx 2>/dev/null || true fi fi done -# Start nginx again -print_status "Starting nginx..." -systemctl start nginx 2>/dev/null || true - -# Set up automatic renewal cron job -print_status "Setting up automatic certificate renewal..." - -CRON_JOB="0 12 * * * /usr/bin/certbot renew --quiet --post-hook \"systemctl reload nginx\"" - -# Check if cron job already exists -if ! crontab -l 2>/dev/null | grep -q "certbot renew"; then - # Add cron job - (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab - - print_success "Automatic renewal cron job added" -else - print_success "Automatic renewal cron job already exists" +# Ensure nginx is running +if ! systemctl is-active --quiet nginx; then + print_status "Starting nginx..." + systemctl start nginx fi -# Test renewal +# Set up automatic renewal cron job (uses nginx plugin, no downtime) +print_status "Setting up automatic certificate renewal..." + +# Remove old cron jobs that might cause issues +crontab -l 2>/dev/null | grep -v "certbot" | crontab - 2>/dev/null || true + +# Add single renewal job that uses nginx plugin +CRON_JOB="0 3 * * * /usr/bin/certbot renew --quiet --deploy-hook \"systemctl reload nginx\"" + +(crontab -l 2>/dev/null | grep -v certbot; echo "$CRON_JOB") | crontab - +print_success "Automatic renewal cron job configured" + +# Test renewal (dry-run) print_status "Testing certificate renewal..." -if certbot renew --dry-run; then +if certbot renew --dry-run 2>&1 | grep -q "Congratulations\|would have been renewed\|No renewals were attempted"; then print_success "Certificate renewal test passed" else - print_warning "Certificate renewal test failed - check configuration" + print_warning "Certificate renewal test had issues - check /var/log/letsencrypt/letsencrypt.log" fi echo "" print_success "SSL certificate setup completed!" echo "" echo "📋 Summary:" -echo "- Certificates obtained for all domains" -echo "- Automatic renewal configured" -echo "- Nginx restarted and configured" +echo "- Certificates configured for: ${DOMAINS[*]}" +echo "- Using nginx plugin (no downtime during renewal)" +echo "- Automatic renewal scheduled at 3:00 AM daily" echo "" echo "🔍 Run './check_ssl.sh' to verify certificate status" echo "🔄 Certificates will auto-renew before expiration"