72 行
2.7 KiB
Bash
72 行
2.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
|
|
. "$ROOT_DIR/scripts/lib.sh"
|
||
|
|
load_env
|
||
|
|
|
||
|
|
DRY_RUN=false
|
||
|
|
[ "${1:-}" = "--dry-run" ] && DRY_RUN=true
|
||
|
|
|
||
|
|
CERT_DIR="${CERT_DIR:-$ROOT_DIR/config/nginx/certs}"
|
||
|
|
DOMAIN="${CONSOLE_DOMAIN:-}"
|
||
|
|
DOMAIN="${DOMAIN#https://}"
|
||
|
|
DOMAIN="${DOMAIN%%/*}"
|
||
|
|
|
||
|
|
audit "renew-cert" "STARTED" "domain=$DOMAIN dry_run=$DRY_RUN"
|
||
|
|
progress "renew-cert" "STARTED" "domain=$DOMAIN"
|
||
|
|
|
||
|
|
[ -n "$DOMAIN" ] || fail_json "XUQM_PRIVATE_5010" "CONSOLE_DOMAIN not set" "renew-cert"
|
||
|
|
|
||
|
|
mkdir -p "$CERT_DIR"
|
||
|
|
|
||
|
|
# Backup existing certs
|
||
|
|
CERT_FILE="$CERT_DIR/${DOMAIN}.crt"
|
||
|
|
KEY_FILE="$CERT_DIR/${DOMAIN}.key"
|
||
|
|
if [ -f "$CERT_FILE" ]; then
|
||
|
|
CERT_BACKUP="${CERT_FILE}.$(date +%Y%m%d%H%M%S).bak"
|
||
|
|
cp "$CERT_FILE" "$CERT_BACKUP"
|
||
|
|
cp "$KEY_FILE" "${KEY_FILE}.$(date +%Y%m%d%H%M%S).bak"
|
||
|
|
audit "renew-cert" "BACKUP_DONE" "backed up to $CERT_BACKUP"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ "$DRY_RUN" = "true" ]; then
|
||
|
|
printf '[DRY-RUN] Would renew certificate for %s\n' "$DOMAIN"
|
||
|
|
printf '[DRY-RUN] Would reload nginx after renewal\n'
|
||
|
|
audit "renew-cert" "DRY_RUN" "domain=$DOMAIN"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Try acme.sh first, then certbot
|
||
|
|
if command -v acme.sh >/dev/null 2>&1; then
|
||
|
|
acme.sh --renew -d "$DOMAIN" --force 2>&1 | tee -a "$ROOT_DIR/logs/cert-renew.log" || {
|
||
|
|
audit "renew-cert" "FAILED" "acme.sh renewal failed for $DOMAIN"
|
||
|
|
"$ROOT_DIR/scripts/alert-webhook.sh" "CERT_RENEW_FAILED" "Certificate renewal failed for $DOMAIN" 2>/dev/null || true
|
||
|
|
fail_json "XUQM_PRIVATE_5011" "certificate renewal failed for $DOMAIN" "renew-cert"
|
||
|
|
}
|
||
|
|
# Copy renewed cert to nginx config dir
|
||
|
|
acme.sh --install-cert -d "$DOMAIN" \
|
||
|
|
--cert-file "$CERT_FILE" \
|
||
|
|
--key-file "$KEY_FILE" \
|
||
|
|
--reloadcmd "docker exec $(compose ps -q nginx | head -1) nginx -s reload" 2>/dev/null || true
|
||
|
|
elif command -v certbot >/dev/null 2>&1; then
|
||
|
|
certbot renew --cert-name "$DOMAIN" --non-interactive 2>&1 | tee -a "$ROOT_DIR/logs/cert-renew.log" || {
|
||
|
|
audit "renew-cert" "FAILED" "certbot renewal failed for $DOMAIN"
|
||
|
|
"$ROOT_DIR/scripts/alert-webhook.sh" "CERT_RENEW_FAILED" "Certificate renewal failed for $DOMAIN" 2>/dev/null || true
|
||
|
|
fail_json "XUQM_PRIVATE_5011" "certificate renewal failed for $DOMAIN" "renew-cert"
|
||
|
|
}
|
||
|
|
# Reload nginx
|
||
|
|
NGINX_CTR="$(compose ps -q nginx 2>/dev/null | head -1 || true)"
|
||
|
|
[ -n "$NGINX_CTR" ] && docker exec "$NGINX_CTR" nginx -s reload
|
||
|
|
else
|
||
|
|
fail_json "XUQM_PRIVATE_5012" "neither acme.sh nor certbot found" "renew-cert"
|
||
|
|
fi
|
||
|
|
|
||
|
|
audit "renew-cert" "DONE" "domain=$DOMAIN"
|
||
|
|
progress "renew-cert" "DONE" "domain=$DOMAIN"
|
||
|
|
printf 'Certificate renewed for %s\n' "$DOMAIN"
|
||
|
|
|
||
|
|
# Crontab setup hint (output to stdout)
|
||
|
|
printf '\n# Add to crontab for automatic renewal:\n'
|
||
|
|
printf '# 0 3 * * * %s/scripts/renew-cert.sh >> %s/logs/cert-renew.log 2>&1\n' "$ROOT_DIR" "$ROOT_DIR"
|