Files
drone-detector/ssl/certbot-manager.sh
2025-09-12 21:39:21 +02:00

292 lines
9.2 KiB
Bash

#!/bin/bash
# SSL Certificate Management Script for dev.uggla.uamils.com
# This script manages Let's Encrypt certificates for use with external nginx
set -e
# Configuration
DOMAIN="${DOMAIN:-dev.uggla.uamils.com}"
EMAIL="${EMAIL:-admin@uggla.uamils.com}"
RENEWAL_DAYS="${RENEWAL_DAYS:-10}"
CERT_DIR="/etc/letsencrypt"
WEBROOT_PATH="/var/www/html"
LOG_FILE="/var/log/letsencrypt/renewal.log"
# Loopia API credentials (optional, for DNS challenge)
LOOPIA_USER="${LOOPIA_USER:-}"
LOOPIA_PASSWORD="${LOOPIA_PASSWORD:-}"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
check_dependencies() {
local missing_deps=()
if ! command -v certbot >/dev/null 2>&1; then
missing_deps+=("certbot")
fi
if ! command -v nginx >/dev/null 2>&1; then
missing_deps+=("nginx")
fi
if ! command -v openssl >/dev/null 2>&1; then
missing_deps+=("openssl")
fi
if [[ ${#missing_deps[@]} -gt 0 ]]; then
log "ERROR: Missing dependencies: ${missing_deps[*]}"
log "Please install missing packages and try again"
exit 1
fi
}
check_certificate_expiry() {
local cert_path="$CERT_DIR/live/$DOMAIN/cert.pem"
if [[ ! -f "$cert_path" ]]; then
log "Certificate not found at $cert_path - will attempt to obtain new certificate"
return 1
fi
# Get certificate expiry date
local expiry_date=$(openssl x509 -in "$cert_path" -noout -enddate | cut -d= -f2)
local expiry_epoch=$(date -d "$expiry_date" +%s)
local current_epoch=$(date +%s)
local days_until_expiry=$(( (expiry_epoch - current_epoch) / 86400 ))
log "Certificate expires in $days_until_expiry days"
if [[ $days_until_expiry -le $RENEWAL_DAYS ]]; then
log "Certificate expires in $days_until_expiry days - renewal needed"
return 1
else
log "Certificate is valid for $days_until_expiry more days - no renewal needed"
return 0
fi
}
attempt_dns_challenge() {
log "Attempting DNS challenge..."
if [[ -z "$LOOPIA_USER" || -z "$LOOPIA_PASSWORD" ]]; then
log "LOOPIA_USER or LOOPIA_PASSWORD not set - skipping DNS challenge"
return 1
fi
# Check if dns-lexicon is available
if command -v lexicon >/dev/null 2>&1; then
log "Using dns-lexicon for DNS challenge..."
certbot certonly \
--dns-lexicon \
--dns-lexicon-provider loopia \
--dns-lexicon-loopia-username="$LOOPIA_USER" \
--dns-lexicon-loopia-password="$LOOPIA_PASSWORD" \
--email "$EMAIL" \
--agree-tos \
--non-interactive \
--expand \
-d "$DOMAIN" \
-d "*.$DOMAIN"
return $?
fi
# Fallback: Manual DNS with custom hook
if [[ -f "$(dirname "$0")/loopia-hook.sh" ]]; then
log "Using custom Loopia hook for DNS challenge..."
LOOPIA_USER="$LOOPIA_USER" LOOPIA_PASSWORD="$LOOPIA_PASSWORD" \
certbot certonly \
--manual \
--preferred-challenges dns \
--manual-auth-hook "$(dirname "$0")/loopia-hook.sh auth" \
--manual-cleanup-hook "$(dirname "$0")/loopia-hook.sh cleanup" \
--email "$EMAIL" \
--agree-tos \
--non-interactive \
--expand \
-d "$DOMAIN" \
-d "*.$DOMAIN"
return $?
fi
log "No DNS challenge method available"
return 1
}
attempt_http_challenge() {
log "Attempting HTTP challenge..."
# Ensure webroot directory exists
mkdir -p "$WEBROOT_PATH"
# Check if nginx is configured for ACME challenges
if ! nginx -t 2>/dev/null; then
log "WARNING: nginx configuration test failed"
fi
certbot certonly \
--webroot \
--webroot-path="$WEBROOT_PATH" \
--email "$EMAIL" \
--agree-tos \
--non-interactive \
--expand \
-d "$DOMAIN"
return $?
}
reload_nginx() {
log "Reloading nginx configuration..."
# Test nginx configuration first
if nginx -t; then
systemctl reload nginx || service nginx reload || nginx -s reload
log "Nginx reloaded successfully"
# Auto-configure nginx with SSL if setup script exists
local ssl_setup_script="$(dirname "$0")/nginx-ssl-setup.sh"
if [[ -f "$ssl_setup_script" ]] && [[ ! -f "/etc/nginx/sites-available/$DOMAIN" ]]; then
log "SSL configuration not found - setting up nginx SSL configuration..."
if bash "$ssl_setup_script" setup; then
log "✅ Nginx SSL configuration completed automatically"
else
log "⚠️ Nginx SSL auto-configuration failed - please run manually:"
log " sudo $ssl_setup_script"
fi
fi
else
log "ERROR: nginx configuration test failed - not reloading"
return 1
fi
}
show_certificate_info() {
local cert_path="$CERT_DIR/live/$DOMAIN/cert.pem"
if [[ ! -f "$cert_path" ]]; then
log "No certificate found for $DOMAIN"
return 1
fi
log "Certificate Information:"
log "========================"
# Get certificate details
local subject=$(openssl x509 -in "$cert_path" -noout -subject | sed 's/subject=//')
local issuer=$(openssl x509 -in "$cert_path" -noout -issuer | sed 's/issuer=//')
local expiry_date=$(openssl x509 -in "$cert_path" -noout -enddate | cut -d= -f2)
local san=$(openssl x509 -in "$cert_path" -noout -text | grep -A1 "Subject Alternative Name" | tail -1 | sed 's/^[[:space:]]*//')
# Calculate days until expiry
local expiry_epoch=$(date -d "$expiry_date" +%s)
local current_epoch=$(date +%s)
local days_until_expiry=$(( (expiry_epoch - current_epoch) / 86400 ))
log " Domain: $DOMAIN"
log " Subject: $subject"
log " Issuer: $issuer"
log " SAN: $san"
log " Expires: $expiry_date"
log " Days until expiry: $days_until_expiry"
if [[ $days_until_expiry -le $RENEWAL_DAYS ]]; then
log " STATUS: ⚠️ Certificate expires soon - renewal recommended"
elif [[ $days_until_expiry -le 30 ]]; then
log " STATUS: ⚡ Certificate expires in less than 30 days"
else
log " STATUS: ✅ Certificate is valid"
fi
}
main() {
# Create log directory
mkdir -p "$(dirname "$LOG_FILE")"
log "Starting SSL certificate management for $DOMAIN"
# Check dependencies
check_dependencies
case "${1:-check}" in
"check")
log "Checking certificate status..."
if check_certificate_expiry; then
log "Certificate is valid - no action needed"
show_certificate_info
exit 0
else
log "Certificate renewal required"
exit 1
fi
;;
"renew")
log "Forcing certificate renewal..."
# Try DNS challenge first (for wildcard support)
if attempt_dns_challenge; then
log "DNS challenge successful!"
reload_nginx
show_certificate_info
log "Certificate renewal completed successfully"
exit 0
fi
# Fallback to HTTP challenge
log "DNS challenge failed - falling back to HTTP challenge"
if attempt_http_challenge; then
log "HTTP challenge successful!"
reload_nginx
show_certificate_info
log "Certificate renewal completed successfully"
exit 0
fi
log "ERROR: All certificate renewal attempts failed"
exit 1
;;
"status"|"info")
show_certificate_info
;;
"auto")
log "Auto-renewal check (runs only if needed)..."
if check_certificate_expiry; then
log "Certificate is valid - no renewal needed"
exit 0
else
log "Certificate needs renewal - attempting automatic renewal"
exec "$0" renew
fi
;;
*)
echo "SSL Certificate Management for $DOMAIN"
echo "======================================"
echo ""
echo "Usage: $0 [command]"
echo ""
echo "Commands:"
echo " check Check if certificate needs renewal"
echo " renew Force certificate renewal"
echo " status Show certificate information"
echo " auto Auto-renew only if needed (for cron)"
echo ""
echo "Environment variables:"
echo " DOMAIN Domain name (default: $DOMAIN)"
echo " EMAIL Email for Let's Encrypt (default: $EMAIL)"
echo " RENEWAL_DAYS Days before expiry to renew (default: $RENEWAL_DAYS)"
echo " LOOPIA_USER Loopia username for DNS challenge"
echo " LOOPIA_PASSWORD Loopia password for DNS challenge"
exit 0
;;
esac
}
# Run main function
main "$@"