diff --git a/NGINX_PROXY_SETUP.md b/NGINX_PROXY_SETUP.md new file mode 100644 index 0000000..4dc9c68 --- /dev/null +++ b/NGINX_PROXY_SETUP.md @@ -0,0 +1,261 @@ +# OPNsense NGINX Reverse Proxy Setup + +Dieses Script automatisiert die Konfiguration eines NGINX Reverse Proxys auf OPNsense für n8n-Instanzen. + +## Voraussetzungen + +- OPNsense Firewall mit NGINX Plugin +- API-Zugang zu OPNsense (API Key + Secret) +- Wildcard-Zertifikat für die Domain (z.B. *.userman.de) + +## Installation + +Das Script befindet sich im Repository unter `setup_nginx_proxy.sh`. + +## Verwendung + +### Proxy einrichten + +```bash +# Minimale Konfiguration +bash setup_nginx_proxy.sh \ + --ctid 768736636 \ + --hostname sb-1768736636 \ + --fqdn sb-1768736636.userman.de \ + --backend-ip 192.168.45.135 + +# Mit Debug-Ausgabe +bash setup_nginx_proxy.sh --debug \ + --ctid 768736636 \ + --hostname sb-1768736636 \ + --fqdn sb-1768736636.userman.de \ + --backend-ip 192.168.45.135 + +# Mit benutzerdefiniertem Backend-Port +bash setup_nginx_proxy.sh \ + --ctid 768736636 \ + --hostname sb-1768736636 \ + --fqdn sb-1768736636.userman.de \ + --backend-ip 192.168.45.135 \ + --backend-port 8080 +``` + +### Proxy löschen + +```bash +# Proxy für eine CTID löschen +bash delete_nginx_proxy.sh --ctid 768736636 + +# Mit Debug-Ausgabe +bash delete_nginx_proxy.sh --debug --ctid 768736636 + +# Dry-Run (zeigt was gelöscht würde, ohne zu löschen) +bash delete_nginx_proxy.sh --dry-run --ctid 768736636 + +# Mit expliziter FQDN +bash delete_nginx_proxy.sh --ctid 768736636 --fqdn sb-1768736636.userman.de +``` + +### Hilfsfunktionen + +```bash +# API-Verbindung testen +bash setup_nginx_proxy.sh --test-connection --debug + +# Verfügbare Zertifikate auflisten +bash setup_nginx_proxy.sh --list-certificates --debug +``` + +## Parameter + +### Erforderliche Parameter (für Proxy-Setup) + +| Parameter | Beschreibung | Beispiel | +|-----------|--------------|----------| +| `--ctid ` | Container ID (wird als Beschreibung verwendet) | `768736636` | +| `--hostname ` | Hostname des Containers | `sb-1768736636` | +| `--fqdn ` | Vollständiger Domainname | `sb-1768736636.userman.de` | +| `--backend-ip ` | IP-Adresse des Backends | `192.168.45.135` | + +### Optionale Parameter + +| Parameter | Beschreibung | Standard | +|-----------|--------------|----------| +| `--backend-port ` | Backend-Port | `5678` | +| `--opnsense-host ` | OPNsense IP oder Hostname | `192.168.45.1` | +| `--opnsense-port ` | OPNsense WebUI/API Port | `4444` | +| `--certificate-uuid ` | UUID des SSL-Zertifikats | Auto-Detect | +| `--debug` | Debug-Modus aktivieren | Aus | +| `--help` | Hilfe anzeigen | - | + +### Spezielle Befehle + +| Parameter | Beschreibung | +|-----------|--------------| +| `--test-connection` | API-Verbindung testen und beenden | +| `--list-certificates` | Verfügbare Zertifikate auflisten und beenden | + +## Ausgabe + +### Normalmodus (ohne --debug) + +Das Script gibt nur JSON auf stdout aus: + +```json +{ + "success": true, + "ctid": "768736636", + "fqdn": "sb-1768736636.userman.de", + "backend": "192.168.45.135:5678", + "nginx": { + "upstream_server_uuid": "81f5f15b-978c-4839-b794-5ddb9f1c964e", + "upstream_uuid": "5fe99a9f-35fb-4141-9b89-238333604a0d", + "location_uuid": "5c3cc080-385a-4800-964d-ab01f33d45a8", + "http_server_uuid": "946489aa-7212-41b3-93e2-4972f6a26d4e" + } +} +``` + +Bei Fehlern: +```json +{"error": "Fehlerbeschreibung"} +``` + +### Debug-Modus (mit --debug) + +Zusätzlich werden Logs auf stderr ausgegeben: + +``` +[2026-01-18 17:57:04] INFO: Script Version: 1.0.8 +[2026-01-18 17:57:04] INFO: Configuration: +[2026-01-18 17:57:04] INFO: CTID: 768736636 +[2026-01-18 17:57:04] INFO: Hostname: sb-1768736636 +... +``` + +## Erstellte NGINX-Komponenten + +Das Script erstellt folgende Komponenten in OPNsense: + +1. **Upstream Server** - Backend-Server mit IP und Port +2. **Upstream** - Load-Balancer-Gruppe (verweist auf Upstream Server) +3. **Location** - URL-Pfad-Konfiguration mit WebSocket-Support +4. **HTTP Server** - Virtueller Host mit HTTPS und Zertifikat + +### Verknüpfungskette + +``` +HTTP Server (sb-1768736636.userman.de:443) + └── Location (/) + └── Upstream (768736636) + └── Upstream Server (192.168.45.135:5678) +``` + +## Umgebungsvariablen + +Das Script kann auch über Umgebungsvariablen konfiguriert werden: + +```bash +export OPNSENSE_HOST="192.168.45.1" +export OPNSENSE_PORT="4444" +export OPNSENSE_API_KEY="your-api-key" +export OPNSENSE_API_SECRET="your-api-secret" +export CERTIFICATE_UUID="your-cert-uuid" +export DEBUG="1" + +bash setup_nginx_proxy.sh --ctid 768736636 ... +``` + +## Delete Script Parameter + +### Erforderliche Parameter + +| Parameter | Beschreibung | Beispiel | +|-----------|--------------|----------| +| `--ctid ` | Container ID (zum Finden der Komponenten) | `768736636` | + +### Optionale Parameter + +| Parameter | Beschreibung | Standard | +|-----------|--------------|----------| +| `--fqdn ` | FQDN zum Finden des HTTP Servers | Auto-Detect | +| `--opnsense-host ` | OPNsense IP oder Hostname | `192.168.45.1` | +| `--opnsense-port ` | OPNsense WebUI/API Port | `4444` | +| `--dry-run` | Zeigt was gelöscht würde, ohne zu löschen | Aus | +| `--debug` | Debug-Modus aktivieren | Aus | + +### Delete Script Ausgabe + +```json +{ + "success": true, + "dry_run": false, + "ctid": "768736636", + "deleted_count": 4, + "failed_count": 0, + "components": { + "http_server": "deleted", + "location": "deleted", + "upstream": "deleted", + "upstream_server": "deleted" + }, + "reconfigure": "ok" +} +``` + +### Löschreihenfolge + +Das Script löscht die Komponenten in der richtigen Reihenfolge (von außen nach innen): + +1. **HTTP Server** - Virtueller Host +2. **Location** - URL-Pfad-Konfiguration +3. **Upstream** - Load-Balancer-Gruppe +4. **Upstream Server** - Backend-Server + +## Fehlerbehebung + +### API-Verbindungsfehler + +```bash +# Verbindung testen +bash setup_nginx_proxy.sh --test-connection --debug +``` + +### Zertifikat nicht gefunden + +```bash +# Verfügbare Zertifikate auflisten +bash setup_nginx_proxy.sh --list-certificates --debug + +# Zertifikat manuell angeben +bash setup_nginx_proxy.sh --certificate-uuid "695a8b67b35ae" ... +``` + +### Berechtigungsfehler (403) + +Der API-Benutzer benötigt folgende Berechtigungen in OPNsense: +- `NGINX: Settings` +- `NGINX: Service` +- `System: Trust: Certificates` (optional, für Auto-Detect) + +## Versionsverlauf + +### setup_nginx_proxy.sh + +| Version | Änderungen | +|---------|------------| +| 1.0.8 | HTTP Server Suche nach servername statt description | +| 1.0.7 | Listen-Adressen auf Port 80/443 gesetzt | +| 1.0.6 | Listen-Adressen hinzugefügt | +| 1.0.5 | verify_client und access_log_format hinzugefügt | +| 1.0.4 | Korrektes API-Format (httpserver statt http_server) | +| 1.0.3 | Vereinfachte HTTP Server Konfiguration | +| 1.0.0 | Initiale Version | + +### delete_nginx_proxy.sh + +| Version | Änderungen | +|---------|------------| +| 1.0.2 | Verbesserte Debug-Ausgabe für Suche nach Komponenten | +| 1.0.1 | Fix: Arithmetik-Fehler bei Counter-Inkrementierung behoben | +| 1.0.0 | Initiale Version | diff --git a/delete_nginx_proxy.sh b/delete_nginx_proxy.sh new file mode 100644 index 0000000..1ecd13e --- /dev/null +++ b/delete_nginx_proxy.sh @@ -0,0 +1,389 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# ============================================================================= +# OPNsense NGINX Reverse Proxy Delete Script +# ============================================================================= +# Dieses Script löscht einen NGINX Reverse Proxy auf OPNsense +# für eine n8n-Instanz über die OPNsense API. +# ============================================================================= + +SCRIPT_VERSION="1.0.2" + +# Debug mode: 0 = nur JSON, 1 = Logs auf stderr +DEBUG="${DEBUG:-0}" +export DEBUG + +# Logging functions +log_ts() { date "+[%F %T]"; } +info() { [[ "$DEBUG" == "1" ]] && echo "$(log_ts) INFO: $*" >&2; return 0; } +warn() { [[ "$DEBUG" == "1" ]] && echo "$(log_ts) WARN: $*" >&2; return 0; } +die() { + if [[ "$DEBUG" == "1" ]]; then + echo "$(log_ts) ERROR: $*" >&2 + else + echo "{\"error\": \"$*\"}" + fi + exit 1 +} + +# ============================================================================= +# Default Configuration +# ============================================================================= +OPNSENSE_HOST="${OPNSENSE_HOST:-192.168.45.1}" +OPNSENSE_PORT="${OPNSENSE_PORT:-4444}" +OPNSENSE_API_KEY="${OPNSENSE_API_KEY:-cUUs80IDkQelMJVgAVK2oUoDHrQf+cQPwXoPKNd3KDIgiCiEyEfMq38UTXeY5/VO/yWtCC7k9Y9kJ0Pn}" +OPNSENSE_API_SECRET="${OPNSENSE_API_SECRET:-2egxxFYCAUjBDp0OrgbJO3NBZmR4jpDm028jeS8Nq8OtCGu/0lAxt4YXWXbdZjcFVMS0Nrhru1I2R1si}" + +# ============================================================================= +# Usage +# ============================================================================= +usage() { + cat >&2 <<'EOF' +Usage: + bash delete_nginx_proxy.sh [options] + +Required options: + --ctid Container ID (used to find components by description) + +Optional: + --fqdn Full domain name (to find HTTP Server by servername) + --opnsense-host OPNsense IP or hostname (default: 192.168.45.1) + --opnsense-port OPNsense WebUI/API port (default: 4444) + --dry-run Show what would be deleted without actually deleting + --debug Enable debug mode + --help Show this help + +Examples: + # Delete proxy by CTID: + bash delete_nginx_proxy.sh --ctid 768736636 + + # Delete proxy with debug output: + bash delete_nginx_proxy.sh --debug --ctid 768736636 + + # Dry run (show what would be deleted): + bash delete_nginx_proxy.sh --dry-run --ctid 768736636 + + # Delete by CTID and FQDN: + bash delete_nginx_proxy.sh --ctid 768736636 --fqdn sb-1768736636.userman.de +EOF +} + +# ============================================================================= +# Default values for arguments +# ============================================================================= +CTID="" +FQDN="" +DRY_RUN="0" + +# ============================================================================= +# Argument parsing +# ============================================================================= +while [[ $# -gt 0 ]]; do + case "$1" in + --ctid) CTID="${2:-}"; shift 2 ;; + --fqdn) FQDN="${2:-}"; shift 2 ;; + --opnsense-host) OPNSENSE_HOST="${2:-}"; shift 2 ;; + --opnsense-port) OPNSENSE_PORT="${2:-}"; shift 2 ;; + --dry-run) DRY_RUN="1"; shift 1 ;; + --debug) DEBUG="1"; export DEBUG; shift 1 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1 (use --help)" ;; + esac +done + +# ============================================================================= +# API Base URL +# ============================================================================= +API_BASE="https://${OPNSENSE_HOST}:${OPNSENSE_PORT}/api" + +# ============================================================================= +# API Helper Functions +# ============================================================================= + +# Make API request to OPNsense +api_request() { + local method="$1" + local endpoint="$2" + local data="${3:-}" + + local url="${API_BASE}${endpoint}" + local auth="${OPNSENSE_API_KEY}:${OPNSENSE_API_SECRET}" + + info "API ${method} ${url}" + + local response + + if [[ -n "$data" ]]; then + response=$(curl -s -k -X "${method}" \ + -u "${auth}" \ + -H "Content-Type: application/json" \ + -d "${data}" \ + "${url}" 2>&1) + else + response=$(curl -s -k -X "${method}" \ + -u "${auth}" \ + "${url}" 2>&1) + fi + + echo "$response" +} + +# Search for items by description +search_by_description() { + local search_endpoint="$1" + local description="$2" + + local response + response=$(api_request "GET" "${search_endpoint}") + + info "Search response for ${search_endpoint}: ${response:0:500}..." + + # Extract all UUIDs where description matches + local uuid + uuid=$(echo "$response" | python3 -c " +import json, sys +desc = sys.argv[1] if len(sys.argv) > 1 else '' +try: + data = json.load(sys.stdin) + rows = data.get('rows', []) + for row in rows: + row_desc = row.get('description', '') + if row_desc == desc: + print(row.get('uuid', '')) + sys.exit(0) +except Exception as e: + print(f'Error: {e}', file=sys.stderr) +" "${description}" 2>/dev/null || true) + + info "Found UUID for description '${description}': ${uuid:-none}" + echo "$uuid" +} + +# Search for HTTP Server by servername +search_http_server_by_servername() { + local servername="$1" + + local response + response=$(api_request "GET" "/nginx/settings/searchHttpServer") + + info "HTTP Server search response: ${response:0:500}..." + + # Extract UUID where servername matches + local uuid + uuid=$(echo "$response" | python3 -c " +import json, sys +sname = sys.argv[1] if len(sys.argv) > 1 else '' +try: + data = json.load(sys.stdin) + rows = data.get('rows', []) + for row in rows: + row_sname = row.get('servername', '') + if row_sname == sname: + print(row.get('uuid', '')) + sys.exit(0) +except Exception as e: + print(f'Error: {e}', file=sys.stderr) +" "${servername}" 2>/dev/null || true) + + info "Found HTTP Server UUID for servername '${servername}': ${uuid:-none}" + echo "$uuid" +} + +# ============================================================================= +# Delete Functions +# ============================================================================= + +delete_item() { + local item_type="$1" + local uuid="$2" + local endpoint="$3" + + if [[ -z "$uuid" ]]; then + info "No ${item_type} found to delete" + return 0 + fi + + if [[ "$DRY_RUN" == "1" ]]; then + info "[DRY-RUN] Would delete ${item_type}: ${uuid}" + echo "dry-run" + return 0 + fi + + info "Deleting ${item_type}: ${uuid}" + local response + response=$(api_request "POST" "${endpoint}/${uuid}") + + local result + result=$(echo "$response" | python3 -c "import json,sys; print(json.load(sys.stdin).get('result','unknown'))" 2>/dev/null || echo "unknown") + + if [[ "$result" == "deleted" ]]; then + info "${item_type} deleted successfully" + echo "deleted" + else + warn "Failed to delete ${item_type}: ${response}" + echo "failed" + fi +} + +# ============================================================================= +# Validation +# ============================================================================= +[[ -n "$CTID" ]] || die "--ctid is required" + +info "Script Version: ${SCRIPT_VERSION}" +info "Configuration:" +info " CTID: ${CTID}" +info " FQDN: ${FQDN:-auto-detect}" +info " OPNsense: ${OPNSENSE_HOST}:${OPNSENSE_PORT}" +info " Dry Run: ${DRY_RUN}" + +# ============================================================================= +# Main +# ============================================================================= +main() { + info "Starting NGINX Reverse Proxy deletion for CTID ${CTID}..." + + local description="${CTID}" + local deleted_count=0 + local failed_count=0 + + # Results tracking + local http_server_result="not_found" + local location_result="not_found" + local upstream_result="not_found" + local upstream_server_result="not_found" + + # Step 1: Find and delete HTTP Server + info "Step 1: Finding HTTP Server..." + local http_server_uuid="" + + # Try to find by FQDN first + if [[ -n "$FQDN" ]]; then + http_server_uuid=$(search_http_server_by_servername "${FQDN}") + fi + + # If not found by FQDN, try common patterns + if [[ -z "$http_server_uuid" ]]; then + # Try sb-.userman.de pattern + http_server_uuid=$(search_http_server_by_servername "sb-${CTID}.userman.de") + fi + + if [[ -z "$http_server_uuid" ]]; then + # Try sb-1.userman.de pattern (with leading 1) + http_server_uuid=$(search_http_server_by_servername "sb-1${CTID}.userman.de") + fi + + if [[ -n "$http_server_uuid" ]]; then + http_server_result=$(delete_item "HTTP Server" "$http_server_uuid" "/nginx/settings/delHttpServer") + if [[ "$http_server_result" == "deleted" || "$http_server_result" == "dry-run" ]]; then + deleted_count=$((deleted_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + else + info "No HTTP Server found for CTID ${CTID}" + fi + + # Step 2: Find and delete Location + info "Step 2: Finding Location..." + local location_uuid + location_uuid=$(search_by_description "/nginx/settings/searchLocation" "${description}") + + if [[ -n "$location_uuid" ]]; then + location_result=$(delete_item "Location" "$location_uuid" "/nginx/settings/delLocation") + if [[ "$location_result" == "deleted" || "$location_result" == "dry-run" ]]; then + deleted_count=$((deleted_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + else + info "No Location found for CTID ${CTID}" + fi + + # Step 3: Find and delete Upstream + info "Step 3: Finding Upstream..." + local upstream_uuid + upstream_uuid=$(search_by_description "/nginx/settings/searchUpstream" "${description}") + + if [[ -n "$upstream_uuid" ]]; then + upstream_result=$(delete_item "Upstream" "$upstream_uuid" "/nginx/settings/delUpstream") + if [[ "$upstream_result" == "deleted" || "$upstream_result" == "dry-run" ]]; then + deleted_count=$((deleted_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + else + info "No Upstream found for CTID ${CTID}" + fi + + # Step 4: Find and delete Upstream Server + info "Step 4: Finding Upstream Server..." + local upstream_server_uuid + upstream_server_uuid=$(search_by_description "/nginx/settings/searchUpstreamServer" "${description}") + + if [[ -n "$upstream_server_uuid" ]]; then + upstream_server_result=$(delete_item "Upstream Server" "$upstream_server_uuid" "/nginx/settings/delUpstreamServer") + if [[ "$upstream_server_result" == "deleted" || "$upstream_server_result" == "dry-run" ]]; then + deleted_count=$((deleted_count + 1)) + else + failed_count=$((failed_count + 1)) + fi + else + info "No Upstream Server found for CTID ${CTID}" + fi + + # Step 5: Apply configuration (if not dry-run and something was deleted) + local reconfigure_result="skipped" + if [[ "$DRY_RUN" != "1" && $deleted_count -gt 0 ]]; then + info "Step 5: Applying NGINX configuration..." + local response + response=$(api_request "POST" "/nginx/service/reconfigure" "{}") + + local status + status=$(echo "$response" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status',''))" 2>/dev/null || echo "unknown") + + if [[ "$status" == "ok" ]]; then + info "NGINX configuration applied successfully" + reconfigure_result="ok" + else + warn "NGINX reconfigure status: ${status}" + reconfigure_result="failed" + fi + elif [[ "$DRY_RUN" == "1" ]]; then + info "[DRY-RUN] Would apply NGINX configuration" + reconfigure_result="dry-run" + fi + + # Output result as JSON + local success="true" + [[ $failed_count -gt 0 ]] && success="false" + + local result + result=$(cat </dev/null || echo "$result" + fi +} + +main diff --git a/delete_stopped_lxcs.sh b/delete_stopped_lxcs.sh index 0ef378d..cc63e7c 100755 --- a/delete_stopped_lxcs.sh +++ b/delete_stopped_lxcs.sh @@ -1,52 +1,69 @@ #!/bin/bash +# delete_stopped_lxc.sh - Löscht alle gestoppten LXC Container auf PVE -# Skript zum Löschen aller gestoppten LXCs auf dem lokalen Proxmox-Node -# Verwendet pct destroy und berücksichtigt nur den lokalen Node +set -e -# Überprüfen, ob das Skript als Root ausgeführt wird -if [ "$(id -u)" -ne 0 ]; then - echo "Dieses Skript muss als Root ausgeführt werden." >&2 - exit 1 -fi +# Farben für Output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color -# Überprüfen, ob pct verfügbar ist -if ! command -v pct &> /dev/null; then - echo "pct ist nicht installiert. Bitte installieren Sie es zuerst." >&2 - exit 1 -fi +echo -e "${YELLOW}=== Gestoppte LXC Container finden ===${NC}\n" -# Alle gestoppten LXCs auf dem lokalen Node abrufen -echo "Suche nach gestoppten LXCs auf diesem Node..." -stopped_lxcs=$(pct list | awk '$2 == "stopped" {print $1}') +# Array für gestoppte Container +declare -a STOPPED_CTS -if [ -z "$stopped_lxcs" ]; then - echo "Keine gestoppten LXCs auf diesem Node gefunden." +# Alle Container durchgehen und gestoppte finden +while read -r line; do + VMID=$(echo "$line" | awk '{print $1}') + STATUS=$(echo "$line" | awk '{print $2}') + NAME=$(echo "$line" | awk '{print $3}') + + if [[ "$STATUS" == "stopped" ]]; then + STOPPED_CTS+=("$VMID:$NAME") + echo -e " ${RED}[STOPPED]${NC} CT $VMID - $NAME" + fi +done < <(pct list | tail -n +2) + +# Prüfen ob gestoppte Container gefunden wurden +if [[ ${#STOPPED_CTS[@]} -eq 0 ]]; then + echo -e "\n${GREEN}Keine gestoppten Container gefunden.${NC}" exit 0 fi -echo "Gefundene gestoppte LXCs auf diesem Node:" -echo "$stopped_lxcs" | while read -r lxc_id; do - lxc_name=$(pct config $lxc_id | grep '^hostname:' | awk '{print $2}') - echo " $lxc_id - $lxc_name" -done +echo -e "\n${YELLOW}Gefunden: ${#STOPPED_CTS[@]} gestoppte Container${NC}\n" -# Bestätigung einholen -read -p "Möchten Sie diese LXCs wirklich löschen? (y/n): " confirm -if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - echo "Löschvorgang abgebrochen." +# Bestätigung anfordern +read -p "Möchten Sie ALLE gestoppten Container unwiderruflich löschen? (ja/nein): " CONFIRM + +if [[ "$CONFIRM" != "ja" ]]; then + echo -e "${GREEN}Abgebrochen. Keine Container wurden gelöscht.${NC}" exit 0 fi -# LXCs löschen -echo "Lösche gestoppte LXCs..." -for lxc_id in $stopped_lxcs; do - echo "Lösche LXC $lxc_id..." - pct destroy $lxc_id - if [ $? -eq 0 ]; then - echo "LXC $lxc_id erfolgreich gelöscht." +# Zweite Bestätigung +read -p "Sind Sie WIRKLICH sicher? Tippen Sie 'LÖSCHEN' ein: " CONFIRM2 + +if [[ "$CONFIRM2" != "LÖSCHEN" ]]; then + echo -e "${GREEN}Abgebrochen. Keine Container wurden gelöscht.${NC}" + exit 0 +fi + +echo -e "\n${RED}=== Lösche Container ===${NC}\n" + +# Container löschen +for CT in "${STOPPED_CTS[@]}"; do + VMID="${CT%%:*}" + NAME="${CT##*:}" + + echo -n "Lösche CT $VMID ($NAME)... " + + if pct destroy "$VMID" --purge 2>/dev/null; then + echo -e "${GREEN}OK${NC}" else - echo "Fehler beim Löschen von LXC $lxc_id." >&2 + echo -e "${RED}FEHLER${NC}" fi done -echo "Vorgang abgeschlossen." \ No newline at end of file +echo -e "\n${GREEN}=== Fertig ===${NC}" \ No newline at end of file