Simplify certificate renewal scripts and add certbot cleanup
All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 59s

Simplified all certificate renewal scripts to be more straightforward and reliable:
- Scripts now just run certbot renew and copy cert+key files to HAProxy format
- Removed overly complex retry logic and error handling
- Both in-container and host-side scripts work with cron scheduling

Added automatic certbot cleanup when domains are removed:
- When a domain is deleted via API, certbot certificate is also removed
- Prevents renewal errors for domains that no longer exist in HAProxy
- Cleans up both HAProxy combined cert and Let's Encrypt certificate

Script changes:
- renew-certificates.sh: Simplified to 87 lines (from 215)
- sync-certificates.sh: Simplified to 79 lines (from 200+)
- host-renew-certificates.sh: Simplified to 36 lines (from 40)
- All scripts use same pattern: query DB, copy certs, reload HAProxy

Python changes:
- remove_domain() now calls 'certbot delete' to remove certificates
- Prevents orphaned certificates from causing renewal failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-20 09:56:56 -08:00
parent adc20d6d0b
commit 1d22d789b8
4 changed files with 128 additions and 371 deletions

View File

@@ -1,19 +1,15 @@
#!/usr/bin/env bash
# Certificate Sync Script for HAProxy Manager
# This script syncs all Let's Encrypt certificates to HAProxy format
# Use this to update all certificates regardless of renewal status
# This script syncs all Let's Encrypt certificates to HAProxy format without running certbot renew
set -e
# Configuration
LOG_FILE="${LOG_FILE:-/var/log/haproxy-manager.log}"
ERROR_LOG_FILE="${ERROR_LOG_FILE:-/var/log/haproxy-manager-errors.log}"
HAPROXY_SOCKET="${HAPROXY_SOCKET:-/tmp/haproxy-cli}"
DB_FILE="${DB_FILE:-/etc/haproxy/haproxy_config.db}"
SSL_CERTS_DIR="${SSL_CERTS_DIR:-/etc/haproxy/certs}"
MAX_RETRIES=3
RETRY_DELAY=5
# Logging functions
log_info() {
@@ -24,178 +20,57 @@ log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG_FILE" >> "$ERROR_LOG_FILE"
}
log_warning() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $*" | tee -a "$LOG_FILE"
}
# Check if HAProxy socket exists and is accessible
check_haproxy_socket() {
if [ ! -S "$HAPROXY_SOCKET" ]; then
log_warning "HAProxy socket not found at $HAPROXY_SOCKET"
return 1
fi
# Test socket connectivity
if ! echo "show info" | socat stdio "$HAPROXY_SOCKET" &> /dev/null; then
log_warning "HAProxy socket exists but is not responding"
return 1
fi
return 0
}
# Reload HAProxy configuration
reload_haproxy() {
local retry_count=0
while [ $retry_count -lt $MAX_RETRIES ]; do
if check_haproxy_socket; then
log_info "Reloading HAProxy via socket"
if echo "reload" | socat stdio "$HAPROXY_SOCKET"; then
log_info "HAProxy reloaded successfully"
return 0
else
log_warning "HAProxy reload command failed (attempt $((retry_count + 1))/$MAX_RETRIES)"
fi
else
log_warning "HAProxy socket check failed (attempt $((retry_count + 1))/$MAX_RETRIES)"
fi
retry_count=$((retry_count + 1))
if [ $retry_count -lt $MAX_RETRIES ]; then
sleep $RETRY_DELAY
fi
done
log_error "Failed to reload HAProxy after $MAX_RETRIES attempts"
return 1
}
# Sync all certificate files for HAProxy
sync_all_certificates() {
log_info "Syncing all certificate files to HAProxy format"
# Check if database exists
if [ ! -f "$DB_FILE" ]; then
log_error "Database file not found at $DB_FILE"
return 1
fi
# Check if sqlite3 is available
if ! command -v sqlite3 &> /dev/null; then
log_error "sqlite3 command not found"
return 1
fi
# Ensure SSL certs directory exists
mkdir -p "$SSL_CERTS_DIR"
# Get all domains with SSL enabled from database
local domains
domains=$(sqlite3 "$DB_FILE" "SELECT domain, ssl_cert_path FROM domains WHERE ssl_enabled = 1;" 2>/dev/null)
if [ -z "$domains" ]; then
log_info "No SSL-enabled domains found in database"
return 0
fi
local updated_count=0
local error_count=0
local skipped_count=0
# Process each domain
while IFS='|' read -r domain cert_path; do
if [ -z "$domain" ] || [ -z "$cert_path" ]; then
continue
fi
log_info "Processing certificate for domain: $domain"
local letsencrypt_cert="/etc/letsencrypt/live/${domain}/fullchain.pem"
local letsencrypt_key="/etc/letsencrypt/live/${domain}/privkey.pem"
# Check if Let's Encrypt certificate files exist
if [ ! -f "$letsencrypt_cert" ]; then
log_warning "Certificate not found for $domain at $letsencrypt_cert"
skipped_count=$((skipped_count + 1))
continue
fi
if [ ! -f "$letsencrypt_key" ]; then
log_warning "Private key not found for $domain at $letsencrypt_key"
skipped_count=$((skipped_count + 1))
continue
fi
# Get modification times to check if update is needed
local needs_update=false
if [ ! -f "$cert_path" ]; then
log_info "Combined certificate does not exist for $domain, creating it"
needs_update=true
else
# Check if source files are newer than the combined file
if [ "$letsencrypt_cert" -nt "$cert_path" ] || [ "$letsencrypt_key" -nt "$cert_path" ]; then
log_info "Let's Encrypt certificate is newer than combined file for $domain"
needs_update=true
else
log_info "Certificate for $domain is already up to date"
fi
fi
# Combine certificate and key into single file for HAProxy
if [ "$needs_update" = true ]; then
if cat "$letsencrypt_cert" "$letsencrypt_key" > "$cert_path"; then
log_info "Updated combined certificate for $domain at $cert_path"
updated_count=$((updated_count + 1))
else
log_error "Failed to combine certificate files for $domain"
error_count=$((error_count + 1))
fi
fi
done <<< "$domains"
log_info "Certificate sync completed: $updated_count updated, $skipped_count skipped, $error_count errors"
if [ $error_count -gt 0 ]; then
return 1
fi
# Return success if we updated any certificates
if [ $updated_count -gt 0 ]; then
return 0
fi
# Return special code (2) if nothing needed updating
return 2
}
# Main sync process
log_info "Starting certificate sync process"
if sync_all_certificates; then
SYNC_RESULT=$?
# Check if database exists
if [ ! -f "$DB_FILE" ]; then
log_error "Database file not found at $DB_FILE"
exit 1
fi
if [ $SYNC_RESULT -eq 0 ]; then
log_info "Certificates were updated, reloading HAProxy"
if reload_haproxy; then
log_info "Certificate sync and HAProxy reload completed successfully"
exit 0
# Ensure SSL certs directory exists
mkdir -p "$SSL_CERTS_DIR"
# Get all SSL-enabled domains from database
DOMAINS=$(sqlite3 "$DB_FILE" "SELECT domain FROM domains WHERE ssl_enabled = 1;" 2>/dev/null)
if [ -z "$DOMAINS" ]; then
log_info "No SSL-enabled domains found"
exit 0
fi
# Copy certificates for each domain
UPDATED=0
FAILED=0
while read -r domain; do
CERT_FILE="/etc/letsencrypt/live/${domain}/fullchain.pem"
KEY_FILE="/etc/letsencrypt/live/${domain}/privkey.pem"
COMBINED_FILE="${SSL_CERTS_DIR}/${domain}.pem"
if [ -f "$CERT_FILE" ] && [ -f "$KEY_FILE" ]; then
# Combine cert and key into single file for HAProxy
if cat "$CERT_FILE" "$KEY_FILE" > "$COMBINED_FILE"; then
log_info "Updated certificate for $domain"
UPDATED=$((UPDATED + 1))
else
log_error "Certificate sync succeeded but HAProxy reload failed"
exit 1
log_error "Failed to combine certificate for $domain"
FAILED=$((FAILED + 1))
fi
elif [ $SYNC_RESULT -eq 2 ]; then
log_info "All certificates are already up to date, no reload needed"
exit 0
fi
else
SYNC_RESULT=$?
if [ $SYNC_RESULT -eq 2 ]; then
log_info "All certificates are already up to date, no reload needed"
exit 0
else
log_error "Certificate sync failed"
log_error "Certificate files not found for $domain"
FAILED=$((FAILED + 1))
fi
done <<< "$DOMAINS"
log_info "Certificate sync completed: $UPDATED updated, $FAILED failed"
# Reload HAProxy if any certificates were updated
if [ $UPDATED -gt 0 ]; then
if echo "reload" | socat stdio /tmp/haproxy-cli 2>/dev/null; then
log_info "HAProxy reloaded successfully"
else
log_error "Failed to reload HAProxy"
exit 1
fi
fi