#!/usr/bin/env bash # Remove NPMplus certificates that are NOT assigned to any proxy host (inactive/duplicate). # Uses NPM API only (no SSH). Safe: only deletes certs that no proxy host references. # Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. See docs/04-configuration/NPMPLUS_TLS_CLEANUP.md set -euo pipefail # Load IP configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # Load .env if [ -f "$PROJECT_ROOT/.env" ]; then set +u set -a # shellcheck source=/dev/null source "$PROJECT_ROOT/.env" 2>/dev/null || true set +a set -u fi RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } DRY_RUN="${1:-false}" NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}" NPM_EMAIL="${NPM_EMAIL:-admin@example.org}" NPM_PASSWORD="${NPM_PASSWORD:-}" if [ -z "$NPM_PASSWORD" ]; then log_error "NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=..." exit 1 fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🧹 NPMplus – Remove inactive (unused) certificates" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" if [ "$DRY_RUN" = "true" ] || [ "$DRY_RUN" = "1" ]; then log_warn "DRY RUN – no certificates will be deleted" echo "" fi # Authenticate log_info "Authenticating to NPMplus..." AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}') TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON") TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "") if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then log_error "Authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD." exit 1 fi log_success "Authenticated" echo "" # Get proxy hosts – collect certificate_id in use log_info "Fetching proxy hosts..." PROXY_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN") IN_USE_IDS=$(echo "$PROXY_JSON" | jq -r '[.[] | select(.certificate_id != null and .certificate_id > 0) | .certificate_id] | unique[]' 2>/dev/null || true) echo "$IN_USE_IDS" | grep -q . || IN_USE_IDS="" log_info "Certificate IDs in use (assigned to proxy hosts): $(echo $IN_USE_IDS | tr '\n' ' ')" echo "" # Get all certificates log_info "Fetching certificates..." CERTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/certificates" -H "Authorization: Bearer $TOKEN") CERT_COUNT=$(echo "$CERTS_JSON" | jq 'length' 2>/dev/null || echo "0") log_info "Total certificates: $CERT_COUNT" echo "" # Find certs not in use TO_DELETE="" while IFS= read -r cert; do [ -z "$cert" ] && continue cid=$(echo "$cert" | jq -r '.id' 2>/dev/null) [ -z "$cid" ] || [ "$cid" = "null" ] && continue if echo "$IN_USE_IDS" | grep -q "^${cid}$"; then continue fi TO_DELETE="$TO_DELETE $cid" done < <(echo "$CERTS_JSON" | jq -c '.[]' 2>/dev/null) TO_DELETE=$(echo "$TO_DELETE" | xargs) DELETE_COUNT=0 if [ -z "$TO_DELETE" ]; then log_success "No inactive certificates to remove (all certs are in use)." echo "" exit 0 fi DELETE_NUM=$(echo "$TO_DELETE" | wc -w) log_warn "Found $DELETE_NUM certificate(s) not assigned to any proxy host (will remove): $TO_DELETE" echo "" if [ "$DRY_RUN" = "true" ] || [ "$DRY_RUN" = "1" ]; then log_info "[DRY RUN] Would delete certificate IDs: $TO_DELETE" echo "" exit 0 fi # Delete each unused cert via API for cid in $TO_DELETE; do log_info "Deleting certificate ID: $cid" DEL_RESP=$(curl -s -k -w "\n%{http_code}" -X DELETE "$NPM_URL/api/nginx/certificates/$cid" -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$DEL_RESP" | tail -n1) BODY=$(echo "$DEL_RESP" | sed '$d') if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "204" ]; then log_success " ✓ Deleted certificate ID: $cid" DELETE_COUNT=$((DELETE_COUNT + 1)) else log_error " ✗ Failed to delete certificate ID: $cid (HTTP $HTTP_CODE)" echo "$BODY" | jq -r '.message // .error // .' 2>/dev/null || echo "$BODY" fi sleep 1 done echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_success "Removed $DELETE_COUNT inactive certificate(s)." echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" log_info "Refresh NPMplus TLS Certificates page to see the cleanup." echo ""