#!/bin/bash # =================================================================== # MYP Druckerverwaltung - KONSOLIDIERTES SETUP-SKRIPT (OPTIMIERT) # Kombiniert alle Installationsfunktionen in einer einzigen Datei # Optimiert für Debian/Linux (Raspberry Pi OS) - KEIN Windows-Support # HTTPS auf Port 443 mit automatischer SSL-Zertifikat-Generierung # Kiosk-Modus mit Chromium-Autostart ohne Desktop-Environment # Version: 4.1.0 - Robuste Installation mit Retry-Mechanismen # =================================================================== set -euo pipefail # =========================== GLOBALE KONFIGURATION =========================== readonly APP_NAME="MYP Druckerverwaltung" readonly APP_VERSION="4.1.0" readonly APP_DIR="/opt/myp" readonly HTTPS_SERVICE_NAME="myp-https" readonly KIOSK_SERVICE_NAME="myp-kiosk" readonly WATCHDOG_SERVICE_NAME="kiosk-watchdog" readonly WATCHDOG_PYTHON_SERVICE_NAME="kiosk-watchdog-python" readonly FIREWALL_SERVICE_NAME="myp-firewall" readonly KIOSK_USER="kiosk" readonly CURRENT_DIR="$(pwd)" readonly INSTALL_LOG="logs/myp-install.log" readonly ERROR_LOG="logs/myp-install-errors.log" readonly WARNING_LOG="logs/myp-install-warnings.log" readonly DEBUG_LOG="logs/myp-install-debug.log" readonly HTTPS_PORT="443" readonly HTTPS_URL="https://localhost:${HTTPS_PORT}" readonly SYSTEMD_DIR="$CURRENT_DIR/systemd" readonly SYSTEM_SYSTEMD_DIR="/etc/systemd/system" # Retry-Konfiguration readonly MAX_RETRIES=3 readonly RETRY_DELAY=5 # Farben für Ausgabe readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly PURPLE='\033[0;35m' readonly CYAN='\033[0;36m' readonly NC='\033[0m' # =========================== VERBESSERTE LOGGING-FUNKTIONEN =========================== # Globale Variablen für Fehler-Tracking ERROR_COUNT=0 WARNING_COUNT=0 # Log-Dateien initialisieren init_logging() { # Erstelle logs-Verzeichnis falls nötig mkdir -p "logs" 2>/dev/null || true # Initialisiere alle Log-Dateien { echo "=================================================================" echo "MYP Installation Log - $(date '+%Y-%m-%d %H:%M:%S')" echo "Script Version: $APP_VERSION" echo "System: $(uname -a)" echo "=================================================================" echo "" } > "$INSTALL_LOG" { echo "=================================================================" echo "MYP Installation FEHLER Log - $(date '+%Y-%m-%d %H:%M:%S')" echo "=================================================================" echo "" } > "$ERROR_LOG" { echo "=================================================================" echo "MYP Installation WARNUNGEN Log - $(date '+%Y-%m-%d %H:%M:%S')" echo "=================================================================" echo "" } > "$WARNING_LOG" { echo "=================================================================" echo "MYP Installation DEBUG Log - $(date '+%Y-%m-%d %H:%M:%S')" echo "=================================================================" echo "" } > "$DEBUG_LOG" } log() { local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1" echo -e "${GREEN}${message}${NC}" | tee -a "$INSTALL_LOG" } error() { local timestamp="$(date '+%Y-%m-%d %H:%M:%S')" local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" local message="[FEHLER] $1" # Erhöhe Fehler-Zähler ((ERROR_COUNT++)) # Ausgabe auf Konsole echo -e "${RED}${message}${NC}" | tee -a "$INSTALL_LOG" # Detaillierte Fehler-Information in Fehler-Log { echo "[$timestamp] FEHLER #$ERROR_COUNT" echo "Quelle: $caller" echo "Nachricht: $1" echo "Arbeitsverzeichnis: $(pwd)" echo "Benutzer: $(whoami)" echo "---" echo "" } >> "$ERROR_LOG" # Debug-Informationen sammeln { echo "[$timestamp] FEHLER AUFGETRETEN - Debug-Info:" echo "Caller: $caller" echo "PWD: $(pwd)" echo "User: $(whoami)" echo "Disk Space: $(df -h / | tail -1)" echo "Memory: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}')" echo "Load Average: $(uptime | awk -F'load average:' '{print $2}')" echo "Recent commands from history:" history | tail -5 2>/dev/null || echo "History nicht verfügbar" echo "===============================================" echo "" } >> "$DEBUG_LOG" exit 1 } warning() { local timestamp="$(date '+%Y-%m-%d %H:%M:%S')" local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" local message="[WARNUNG] $1" # Erhöhe Warnungs-Zähler ((WARNING_COUNT++)) # Ausgabe auf Konsole echo -e "${YELLOW}${message}${NC}" | tee -a "$INSTALL_LOG" # Detaillierte Warnungs-Information in Warnungs-Log { echo "[$timestamp] WARNUNG #$WARNING_COUNT" echo "Quelle: $caller" echo "Nachricht: $1" echo "---" echo "" } >> "$WARNING_LOG" } info() { echo -e "${BLUE}[INFO] $1${NC}" | tee -a "$INSTALL_LOG" } progress() { echo -e "${PURPLE}[FORTSCHRITT] $1${NC}" | tee -a "$INSTALL_LOG" } success() { echo -e "${CYAN}[ERFOLG] $1${NC}" | tee -a "$INSTALL_LOG" } debug() { local timestamp="$(date '+%Y-%m-%d %H:%M:%S')" local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" # Debug sowohl in normales Log als auch Debug-Log echo -e "${BLUE}[DEBUG] $1${NC}" >> "$INSTALL_LOG" { echo "[$timestamp] DEBUG von $caller" echo "$1" echo "---" echo "" } >> "$DEBUG_LOG" } # Fehler-Zusammenfassung anzeigen show_error_summary() { echo "" echo -e "${CYAN}=================================================================${NC}" echo -e "${CYAN} INSTALLATION ABGESCHLOSSEN - FEHLER-ZUSAMMENFASSUNG${NC}" echo -e "${CYAN}=================================================================${NC}" echo "" echo -e "${BLUE}📊 Statistiken:${NC}" echo -e " ${RED}❌ Fehler: $ERROR_COUNT${NC}" echo -e " ${YELLOW}⚠️ Warnungen: $WARNING_COUNT${NC}" echo "" echo -e "${BLUE}📁 Log-Dateien:${NC}" echo -e " 📄 Vollständiges Log: $INSTALL_LOG" echo -e " 🚨 Fehler-Log: $ERROR_LOG" echo -e " ⚠️ Warnungs-Log: $WARNING_LOG" echo -e " 🔍 Debug-Log: $DEBUG_LOG" echo "" if [ $ERROR_COUNT -gt 0 ]; then echo -e "${RED}⚠️ Es sind $ERROR_COUNT Fehler aufgetreten!${NC}" echo -e "${RED} Bitte prüfen Sie: $ERROR_LOG${NC}" echo "" # Zeige die letzten 3 Fehler an if [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then echo -e "${RED}🔍 Letzte Fehler:${NC}" tail -n 20 "$ERROR_LOG" | head -n 15 echo "" fi fi if [ $WARNING_COUNT -gt 0 ]; then echo -e "${YELLOW}⚠️ Es sind $WARNING_COUNT Warnungen aufgetreten${NC}" echo -e "${YELLOW} Bitte prüfen Sie: $WARNING_LOG${NC}" echo "" fi if [ $ERROR_COUNT -eq 0 ] && [ $WARNING_COUNT -eq 0 ]; then echo -e "${GREEN}✅ Installation ohne Fehler oder Warnungen abgeschlossen!${NC}" elif [ $ERROR_COUNT -eq 0 ]; then echo -e "${GREEN}✅ Installation erfolgreich mit $WARNING_COUNT Warnungen${NC}" fi echo -e "${CYAN}=================================================================${NC}" # Erstelle automatische Log-Zusammenfassung create_log_summary } # Automatische Log-Zusammenfassung erstellen create_log_summary() { local summary_file="logs/myp-install-summary.txt" { echo "=================================================================" echo "MYP INSTALLATION ZUSAMMENFASSUNG" echo "Erstellt: $(date '+%Y-%m-%d %H:%M:%S')" echo "=================================================================" echo "" echo "STATISTIKEN:" echo "- Fehler: $ERROR_COUNT" echo "- Warnungen: $WARNING_COUNT" echo "- Script Version: $APP_VERSION" echo "- System: $(uname -a 2>/dev/null || echo 'Unbekannt')" echo "- Hostname: $(hostname 2>/dev/null || echo 'Unbekannt')" echo "- User: $(whoami 2>/dev/null || echo 'Unbekannt')" echo "" echo "SYSTEM-INFORMATIONEN:" echo "- Festplattenspeicher: $(df -h / | tail -1 2>/dev/null || echo 'Nicht verfügbar')" echo "- Arbeitsspeicher: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}' 2>/dev/null || echo 'Nicht verfügbar')" echo "- Python Version: $(python3 --version 2>&1 || echo 'Nicht installiert')" echo "- Node.js Version: $(node --version 2>&1 || echo 'Nicht installiert')" echo "" echo "LOG-DATEIEN:" echo "- Vollständiges Log: $INSTALL_LOG" echo "- Fehler-Log: $ERROR_LOG" echo "- Warnungs-Log: $WARNING_LOG" echo "- Debug-Log: $DEBUG_LOG" echo "" if [ $ERROR_COUNT -gt 0 ] && [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then echo "FEHLER-ÜBERSICHT:" echo "=================" tail -n 50 "$ERROR_LOG" echo "" fi if [ $WARNING_COUNT -gt 0 ] && [ -f "$WARNING_LOG" ] && [ -s "$WARNING_LOG" ]; then echo "WARNUNGS-ÜBERSICHT:" echo "===================" tail -n 30 "$WARNING_LOG" echo "" fi echo "INSTALLATION ABGESCHLOSSEN: $(date '+%Y-%m-%d %H:%M:%S')" echo "=================================================================" } > "$summary_file" # Berechtigung für Zusammenfassungs-Datei setzen chmod 644 "$summary_file" 2>/dev/null || true debug "Log-Zusammenfassung erstellt: $summary_file" } # =========================== RETRY-MECHANISMEN =========================== retry_command() { local cmd="$1" local description="$2" local attempts=0 while [ $attempts -lt $MAX_RETRIES ]; do if eval "$cmd"; then return 0 fi attempts=$((attempts + 1)) if [ $attempts -lt $MAX_RETRIES ]; then warning "$description fehlgeschlagen (Versuch $attempts/$MAX_RETRIES) - wiederhole in ${RETRY_DELAY}s..." # Debug-Information für jeden fehlgeschlagenen Versuch debug "Retry-Versuch für '$description': $attempts/$MAX_RETRIES" debug "Fehlgeschlagener Befehl: $cmd" debug "Aktuelles Arbeitsverzeichnis: $(pwd)" debug "Verfügbarer Speicher: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}' 2>/dev/null || echo 'Unbekannt')" debug "Exit-Code des letzten Befehls: $?" sleep $RETRY_DELAY fi done # Detaillierte Fehler-Information vor dem Beenden debug "CRITICAL: Retry-Mechanismus erschöpft für '$description'" debug "Letzter Befehl: $cmd" debug "Versuche: $MAX_RETRIES" debug "System-Status zum Zeitpunkt des kritischen Fehlers:" debug " - Disk Usage: $(df -h / | tail -1 2>/dev/null || echo 'Nicht verfügbar')" debug " - Memory Usage: $(free -m 2>/dev/null || echo 'Nicht verfügbar')" debug " - Load Average: $(uptime 2>/dev/null | awk -F'load average:' '{print $2}' || echo 'Nicht verfügbar')" debug " - Network Status: $(ip addr show 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' || echo 'Nicht verfügbar')" debug " - APT Status: $(ps aux | grep -i apt | grep -v grep || echo 'Keine APT-Prozesse')" debug " - Python Status: $(python3 --version 2>&1 || echo 'Python nicht verfügbar')" error "$description nach $MAX_RETRIES Versuchen fehlgeschlagen!" } # APT-Pakete mit Retry installieren apt_install_retry() { local packages="$*" local cmd="DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $packages" progress "Installiere Pakete: $packages" retry_command "$cmd" "APT Installation für: $packages" } # =========================== ERWEITERTE SYSTEM-VALIDIERUNG =========================== check_root() { if [ "$EUID" -ne 0 ]; then error "Dieses Skript muss als Root ausgeführt werden: sudo $0" fi export PATH="/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin:$PATH" log "✅ Root-Berechtigung bestätigt" } check_system_resources() { log "=== SYSTEM-RESSOURCEN PRÜFUNG ===" # RAM prüfen (robuster) progress "Prüfe RAM..." local ram_mb="" # Verschiedene Methoden zur RAM-Ermittlung if command -v free >/dev/null 2>&1; then ram_mb=$(free -m 2>/dev/null | awk '/^Mem:/{print $2}' 2>/dev/null || echo "") fi # Fallback über /proc/meminfo if [ -z "$ram_mb" ] && [ -f "/proc/meminfo" ]; then ram_mb=$(grep '^MemTotal:' /proc/meminfo 2>/dev/null | awk '{print int($2/1024)}' 2>/dev/null || echo "") fi if [ -n "$ram_mb" ] && [ "$ram_mb" -gt 0 ] 2>/dev/null; then progress "Verfügbarer RAM: ${ram_mb}MB" if [ "$ram_mb" -lt 512 ] 2>/dev/null; then warning "⚠️ Wenig RAM verfügbar (${ram_mb}MB) - Installation könnte langsam sein" else success "✅ Ausreichend RAM verfügbar (${ram_mb}MB)" fi else warning "⚠️ RAM-Größe konnte nicht ermittelt werden" debug "RAM-Ermittlung fehlgeschlagen: free-Output: $(free -m 2>&1 || echo 'Befehl nicht verfügbar')" fi # Festplattenplatz prüfen (robuster ohne bc) progress "Prüfe Festplattenplatz..." local disk_free_gb="" local disk_free_mb="" if command -v df >/dev/null 2>&1; then # Hole Festplattenplatz in MB disk_free_mb=$(df / 2>/dev/null | awk 'NR==2{print int($4/1024)}' 2>/dev/null || echo "") if [ -n "$disk_free_mb" ] && [ "$disk_free_mb" -gt 0 ] 2>/dev/null; then # Berechne GB ohne bc (einfache Division) disk_free_gb=$(awk -v mb="$disk_free_mb" 'BEGIN{printf "%.1f", mb/1024}' 2>/dev/null || echo "$((disk_free_mb/1024))") progress "Verfügbarer Festplattenplatz: ${disk_free_gb}GB (${disk_free_mb}MB)" # Prüfe ob mindestens 2GB verfügbar (2048 MB) if [ "$disk_free_mb" -lt 2048 ] 2>/dev/null; then warning "⚠️ Wenig Festplattenplatz verfügbar (${disk_free_gb}GB)" else success "✅ Ausreichend Festplattenplatz verfügbar (${disk_free_gb}GB)" fi else warning "⚠️ Festplattenplatz konnte nicht ermittelt werden" debug "Disk-Ermittlung fehlgeschlagen: df-Output: $(df / 2>&1 || echo 'Befehl nicht verfügbar')" fi else warning "⚠️ df-Befehl nicht verfügbar - kann Festplattenplatz nicht prüfen" fi # CPU prüfen (robuster) progress "Prüfe CPU..." local cpu_count="" local cpu_model="" # CPU-Anzahl ermitteln if command -v nproc >/dev/null 2>&1; then cpu_count=$(nproc 2>/dev/null || echo "") fi if [ -z "$cpu_count" ] && [ -f "/proc/cpuinfo" ]; then cpu_count=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo "") fi # CPU-Modell ermitteln if [ -f "/proc/cpuinfo" ]; then cpu_model=$(grep "model name" /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 2>/dev/null | sed 's/^[[:space:]]*//' 2>/dev/null || echo "Unbekannt") fi if [ -n "$cpu_count" ] && [ "$cpu_count" -gt 0 ] 2>/dev/null; then progress "CPU: $cpu_count Kern(e) - $cpu_model" success "✅ CPU-Information erfolgreich ermittelt" else progress "CPU: Unbekannte Anzahl Kerne - $cpu_model" warning "⚠️ CPU-Kern-Anzahl konnte nicht ermittelt werden" debug "CPU-Ermittlung fehlgeschlagen: nproc-Output: $(nproc 2>&1 || echo 'Befehl nicht verfügbar')" fi log "✅ System-Ressourcen-Prüfung abgeschlossen" } check_debian_system() { progress "Prüfe Debian/Raspbian-System..." # Robuste Debian-Erkennung local is_debian=false local debian_version="Unbekannt" # Verschiedene Methoden zur Debian-Erkennung if [ -f /etc/debian_version ]; then debian_version=$(cat /etc/debian_version 2>/dev/null | head -1 | tr -d '\n\r' || echo "Unbekannt") is_debian=true debug "Debian erkannt über /etc/debian_version: $debian_version" fi # Fallback über os-release if [ "$is_debian" = false ] && [ -f /etc/os-release ]; then local os_id=$(grep '^ID=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "") if [[ "$os_id" =~ ^(debian|raspbian|ubuntu)$ ]]; then is_debian=true local os_version=$(grep '^VERSION=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unbekannt") debian_version="$os_id $os_version" debug "Debian-basiertes System erkannt über os-release: $debian_version" fi fi # Fallback über lsb_release if [ "$is_debian" = false ] && command -v lsb_release >/dev/null 2>&1; then local lsb_id=$(lsb_release -si 2>/dev/null | tr '[:upper:]' '[:lower:]' || echo "") if [[ "$lsb_id" =~ ^(debian|raspbian|ubuntu)$ ]]; then is_debian=true debian_version="$lsb_id $(lsb_release -sr 2>/dev/null || echo 'Unbekannt')" debug "Debian-basiertes System erkannt über lsb_release: $debian_version" fi fi if [ "$is_debian" = false ]; then warning "⚠️ System ist möglicherweise nicht Debian/Raspbian-basiert!" warning "⚠️ Installation wird fortgesetzt, könnte aber fehlschlagen" debug "System-Erkennung fehlgeschlagen. Verfügbare Info:" debug " - /etc/debian_version: $([ -f /etc/debian_version ] && echo 'vorhanden' || echo 'nicht vorhanden')" debug " - /etc/os-release: $([ -f /etc/os-release ] && grep '^ID=' /etc/os-release 2>/dev/null || echo 'nicht verfügbar')" debug " - lsb_release: $(command -v lsb_release >/dev/null 2>&1 && lsb_release -si 2>/dev/null || echo 'nicht verfügbar')" else log "✅ Debian/Raspbian-basiertes System erkannt (Version: $debian_version)" fi # Prüfe auf Raspberry Pi (robuster) progress "Prüfe Raspberry Pi Hardware..." local is_raspberry_pi=false local pi_model="Unbekannt" # Methode 1: Device Tree Model if [ -f /proc/device-tree/model ]; then pi_model=$(cat /proc/device-tree/model 2>/dev/null | tr -d '\0\n\r' | head -c 100 || echo "") if [[ "$pi_model" =~ [Rr]aspberry.*[Pp]i ]]; then is_raspberry_pi=true debug "Raspberry Pi erkannt über device-tree: $pi_model" fi fi # Methode 2: CPU Info if [ "$is_raspberry_pi" = false ] && [ -f /proc/cpuinfo ]; then local cpu_hardware=$(grep '^Hardware' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' | head -1 || echo "") local cpu_model=$(grep '^Model' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' | head -1 || echo "") if [[ "$cpu_hardware" =~ [Bb][Cc][Mm] ]] || [[ "$cpu_model" =~ [Rr]aspberry.*[Pp]i ]]; then is_raspberry_pi=true pi_model="$cpu_model ($cpu_hardware)" debug "Raspberry Pi erkannt über cpuinfo: $pi_model" fi fi if [ "$is_raspberry_pi" = true ]; then info "🍓 Raspberry Pi erkannt: $pi_model" progress "Aktiviere Raspberry Pi spezifische Optimierungen..." export RASPBERRY_PI_DETECTED=1 debug "Raspberry Pi Optimierungen aktiviert" else info "💻 Standard-PC/Server System (kein Raspberry Pi)" debug "Kein Raspberry Pi erkannt. Hardware-Info:" debug " - Device Tree: $([ -f /proc/device-tree/model ] && cat /proc/device-tree/model 2>/dev/null | tr -d '\0' || echo 'nicht verfügbar')" debug " - CPU Hardware: $(grep '^Hardware' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' || echo 'nicht verfügbar')" fi # System-Architektur prüfen (robuster) progress "Prüfe System-Architektur..." local arch="" if command -v uname >/dev/null 2>&1; then arch=$(uname -m 2>/dev/null || echo "Unbekannt") info "📐 System-Architektur: $arch" # Architektur-spezifische Hinweise case "$arch" in "aarch64"|"arm64") info " → 64-Bit ARM Architektur erkannt" ;; "armv7l"|"armv6l") info " → 32-Bit ARM Architektur erkannt" ;; "x86_64"|"amd64") info " → 64-Bit x86 Architektur erkannt" ;; "i386"|"i686") info " → 32-Bit x86 Architektur erkannt" ;; *) warning "⚠️ Unbekannte Architektur: $arch" ;; esac else warning "⚠️ uname-Befehl nicht verfügbar - kann Architektur nicht ermitteln" fi # Kernel-Version prüfen (robuster) progress "Prüfe Kernel-Version..." local kernel="" if command -v uname >/dev/null 2>&1; then kernel=$(uname -r 2>/dev/null || echo "Unbekannt") info "🐧 Kernel-Version: $kernel" debug "Vollständige Kernel-Info: $(uname -a 2>/dev/null || echo 'Nicht verfügbar')" else warning "⚠️ Kernel-Version konnte nicht ermittelt werden" fi log "✅ System-Analyse abgeschlossen" } check_internet_connection() { progress "Prüfe Internetverbindung (erweiterte Methoden)..." local connection_ok=false local test_method="" local debug_info="" # Methode 1: DNS-Auflösung (robuster) progress "Teste DNS-Auflösung..." local dns_hosts=("8.8.8.8" "1.1.1.1" "google.com" "cloudflare.com") for host in "${dns_hosts[@]}"; do debug_info="${debug_info}Teste DNS für $host: " # Teste nslookup if command -v nslookup >/dev/null 2>&1; then if timeout 10 nslookup "$host" >/dev/null 2>&1; then connection_ok=true test_method="DNS-Auflösung (nslookup: $host)" debug_info="${debug_info}Erfolg mit nslookup. " break fi debug_info="${debug_info}nslookup fehlgeschlagen. " fi # Teste getent hosts if [ "$connection_ok" = false ] && command -v getent >/dev/null 2>&1; then if timeout 8 getent hosts "$host" >/dev/null 2>&1; then connection_ok=true test_method="DNS-Auflösung (getent: $host)" debug_info="${debug_info}Erfolg mit getent. " break fi debug_info="${debug_info}getent fehlgeschlagen. " fi # Teste ping als Fallback if [ "$connection_ok" = false ] && command -v ping >/dev/null 2>&1; then if timeout 5 ping -c 1 "$host" >/dev/null 2>&1; then connection_ok=true test_method="Netzwerk-Verbindung (ping: $host)" debug_info="${debug_info}Erfolg mit ping. " break fi debug_info="${debug_info}ping fehlgeschlagen. " fi done debug "DNS-Test Details: $debug_info" # Methode 2: HTTP/HTTPS-Tests (robuster) if [ "$connection_ok" = false ]; then progress "Teste HTTP/HTTPS-Verbindungen..." local http_urls=("http://connectivitycheck.gstatic.com/generate_204" "http://detectportal.firefox.com/success.txt" "https://www.google.com") for url in "${http_urls[@]}"; do debug_info="Teste HTTP für $url: " # Teste curl if command -v curl >/dev/null 2>&1; then if timeout 15 curl -s --connect-timeout 8 --max-time 12 --fail "$url" >/dev/null 2>&1; then connection_ok=true test_method="HTTP/HTTPS (curl: $url)" debug_info="${debug_info}Erfolg mit curl. " break fi debug_info="${debug_info}curl fehlgeschlagen. " fi # Teste wget if [ "$connection_ok" = false ] && command -v wget >/dev/null 2>&1; then if timeout 15 wget -q --timeout=8 --tries=1 --spider "$url" 2>/dev/null; then connection_ok=true test_method="HTTP/HTTPS (wget: $url)" debug_info="${debug_info}Erfolg mit wget. " break fi debug_info="${debug_info}wget fehlgeschlagen. " fi debug "HTTP-Test Details: $debug_info" done fi # Methode 3: Lokale Netzwerk-Interface Prüfung if [ "$connection_ok" = false ]; then progress "Prüfe lokale Netzwerk-Interfaces..." local has_network_interface=false # Prüfe ob aktive Netzwerk-Interfaces vorhanden sind if command -v ip >/dev/null 2>&1; then local active_interfaces=$(ip route show default 2>/dev/null | awk '{print $5}' | head -1) if [ -n "$active_interfaces" ]; then has_network_interface=true local interface_ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7}' | head -1 || echo "Unbekannt") info " 📡 Aktives Interface: $active_interfaces (IP: $interface_ip)" debug "Netzwerk-Interface gefunden: $active_interfaces mit IP $interface_ip" fi fi # Fallback über ifconfig if [ "$has_network_interface" = false ] && command -v ifconfig >/dev/null 2>&1; then local active_interfaces=$(ifconfig 2>/dev/null | grep -E '^[a-zA-Z]' | grep -v '^lo' | head -1 | cut -d: -f1) if [ -n "$active_interfaces" ]; then has_network_interface=true info " 📡 Interface erkannt: $active_interfaces" debug "Netzwerk-Interface über ifconfig gefunden: $active_interfaces" fi fi if [ "$has_network_interface" = true ]; then warning "⚠️ Netzwerk-Interface aktiv, aber Internet nicht erreichbar" warning " → Möglicherweise Firewall, Proxy oder DNS-Problem" else warning "⚠️ Keine aktiven Netzwerk-Interfaces gefunden" warning " → Bitte prüfen Sie die Netzwerk-Konfiguration" fi fi # Methode 4: APT-Repository-Test (nur als letzter Test) if [ "$connection_ok" = false ]; then progress "Teste APT-Repository-Zugang (kann länger dauern)..." # Sehr kurzer APT-Test ohne Update if timeout 30 apt-get -qq --print-uris update 2>/dev/null | grep -q 'http'; then connection_ok=true test_method="APT-Repository-Konfiguration" debug "APT-Repositories scheinen konfiguriert zu sein" else debug "APT-Repository-Test fehlgeschlagen" fi fi # Ergebnis-Bewertung if [ "$connection_ok" = true ]; then success "✅ Internetverbindung verfügbar" info " 🔍 Erkannt via: $test_method" # Zusätzliche Informationen (robust) if command -v curl >/dev/null 2>&1; then progress "Ermittle externe IP-Adresse..." local external_ip="" local ip_services=("ifconfig.me" "ipinfo.io/ip" "icanhazip.com") for service in "${ip_services[@]}"; do external_ip=$(timeout 8 curl -s --connect-timeout 5 "$service" 2>/dev/null | head -1 | tr -d '\n\r' || echo "") if [ -n "$external_ip" ] && [[ "$external_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then info " 🌐 Externe IP: $external_ip" debug "Externe IP ermittelt über $service: $external_ip" break fi done if [ -z "$external_ip" ]; then debug "Externe IP konnte nicht ermittelt werden" fi fi else warning "⚠️ Keine Internetverbindung erkannt" info " → Installation wird fortgesetzt, aber Downloads könnten fehlschlagen" warning " → Bitte prüfen Sie die Netzwerkverbindung!" # Debug-Informationen bei fehlgeschlagener Verbindung debug "Internet-Verbindungstest fehlgeschlagen. System-Info:" debug " - DNS-Server: $(cat /etc/resolv.conf 2>/dev/null | grep nameserver | head -3 || echo 'Nicht verfügbar')" debug " - Default Route: $(ip route show default 2>/dev/null || echo 'Nicht verfügbar')" debug " - Network Interfaces: $(ip addr show 2>/dev/null | grep -E '^[0-9]+:' | cut -d: -f2 | tr -d ' ' | grep -v lo | head -3 || echo 'Nicht verfügbar')" fi } # =========================== ROBUSTE SYSTEM-VORBEREITUNG =========================== update_system() { log "=== ROBUSTE SYSTEM-UPDATE ===" progress "Konfiguriere APT für bessere Zuverlässigkeit..." # APT-Konfiguration optimieren cat > /etc/apt/apt.conf.d/99myp-optimized << 'EOF' APT::Acquire::Retries "3"; APT::Acquire::http::Timeout "30"; APT::Acquire::https::Timeout "30"; APT::Acquire::ftp::Timeout "30"; APT::Install-Recommends "false"; APT::Install-Suggests "false"; Dpkg::Options { "--force-confdef"; "--force-confold"; } EOF # Repository-Listen korrigieren falls nötig progress "Validiere APT-Repositories..." if [ -f /etc/apt/sources.list ]; then # Backup erstellen cp /etc/apt/sources.list /etc/apt/sources.list.backup # Prüfe auf problematische Einträge if grep -q "deb-src" /etc/apt/sources.list; then sed -i 's/^deb-src/#deb-src/g' /etc/apt/sources.list log "✅ Source-Repositories deaktiviert (nicht benötigt)" fi fi progress "Aktualisiere Paketlisten mit Retry..." retry_command "apt-get update" "APT Update" progress "Führe System-Upgrade durch..." retry_command "DEBIAN_FRONTEND=noninteractive apt-get upgrade -y" "System Upgrade" progress "Installiere essenzielle System-Tools..." # Grundlegende Tools in optimierter Reihenfolge local essential_packages=( "ca-certificates" "gnupg" "curl" "wget" "git" "nano" "htop" "rsync" "unzip" "sudo" "systemd" "lsb-release" "apt-transport-https" "software-properties-common" "bc" "dbus" "systemd-timesyncd" ) for package in "${essential_packages[@]}"; do apt_install_retry "$package" done # Zeitserver synchronisieren progress "Synchronisiere Systemzeit..." systemctl enable systemd-timesyncd 2>/dev/null || true systemctl start systemd-timesyncd 2>/dev/null || true log "✅ Robustes System-Update abgeschlossen" } # =========================== VERBESSERTE PYTHON-INSTALLATION =========================== install_python_dependencies() { log "=== ROBUSTE PYTHON-INSTALLATION ===" progress "Installiere Python 3 und Build-Abhängigkeiten..." local python_packages=( "python3" "python3-pip" "python3-dev" "python3-setuptools" "python3-venv" "python3-wheel" "build-essential" "libssl-dev" "libffi-dev" "libbz2-dev" "libreadline-dev" "libsqlite3-dev" "libncurses5-dev" "libncursesw5-dev" "zlib1g-dev" "sqlite3" ) for package in "${python_packages[@]}"; do apt_install_retry "$package" done # Python-Version validieren progress "Validiere Python-Installation..." local python_version=$(python3 --version 2>&1 | cut -d' ' -f2) log "✅ Python Version: $python_version" # pip konfigurieren und aktualisieren progress "Konfiguriere pip für bessere Zuverlässigkeit..." # Root pip-Konfiguration mkdir -p /root/.pip cat > /root/.pip/pip.conf << 'EOF' [global] trusted-host = pypi.org pypi.python.org files.pythonhosted.org cert = /etc/ssl/certs/ca-certificates.crt timeout = 120 retries = 5 no-cache-dir = false disable-pip-version-check = true no-warn-script-location = true break-system-packages = true [install] trusted-host = pypi.org pypi.python.org files.pythonhosted.org user = false break-system-packages = true EOF # Systemweite pip-Konfiguration für alle Benutzer progress "Erstelle systemweite pip-Konfiguration..." mkdir -p /etc/pip cat > /etc/pip/pip.conf << 'EOF' [global] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org timeout = 120 retries = 5 disable-pip-version-check = true [install] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org user = false EOF # pip-Konfiguration für existierende Benutzer erstellen progress "Konfiguriere pip für alle Benutzer..." for user_home in "/home/"*; do if [ -d "$user_home" ] && [ "$user_home" != "/home/lost+found" ]; then local username=$(basename "$user_home") if id "$username" &>/dev/null; then mkdir -p "$user_home/.pip" 2>/dev/null || true cat > "$user_home/.pip/pip.conf" << 'EOF' [global] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org timeout = 60 retries = 3 [install] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org EOF chown "$username:$username" "$user_home/.pip/pip.conf" 2>/dev/null || true log "✅ pip konfiguriert für Benutzer: $username" fi fi done # pip selbst aktualisieren progress "Aktualisiere pip mit Retry..." retry_command "python3 -m pip install --break-system-packages --upgrade pip setuptools wheel" "pip Upgrade" # pip-Version validieren local pip_version=$(python3 -m pip --version | cut -d' ' -f2) log "✅ pip Version: $pip_version" log "✅ Robuste Python-Umgebung installiert" } install_python_packages() { log "=== TIMEOUT-GESICHERTE PYTHON-PAKETE INSTALLATION ===" progress "Installiere Python-Pakete mit Timeout-Sicherung..." if [ ! -f "$CURRENT_DIR/requirements.txt" ]; then error "requirements.txt nicht gefunden: $CURRENT_DIR/requirements.txt" fi # Kopiere requirements.txt cp "$CURRENT_DIR/requirements.txt" "$APP_DIR/" 2>/dev/null || true # Timeout-gesicherte pip-Optionen local pip_opts="--break-system-packages --timeout 60 --retries 2 --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --no-cache-dir" # Strategie 1: Direkte Installation mit Timeout progress "Versuche direkte requirements.txt Installation (max 10 Minuten)..." if timeout 600 python3 -m pip install $pip_opts -r "$CURRENT_DIR/requirements.txt" >/dev/null 2>&1; then success "✅ requirements.txt erfolgreich installiert" return 0 else warning "⚠️ Direkte Installation fehlgeschlagen oder Timeout - verwende minimale Installation" debug "requirements.txt Installation nach 600s abgebrochen" # Strategie 2: Nur essenzielle Pakete (timeout-gesichert) progress "Installiere nur essenzielle Flask-Komponenten..." # Minimale Flask-Installation für Funktionalität local essential_deps=( "Flask" "Werkzeug" "Jinja2" "requests" ) local installed_count=0 for dep in "${essential_deps[@]}"; do progress "Installiere essenzielle Abhängigkeit: $dep" if timeout 120 python3 -m pip install $pip_opts "$dep" >/dev/null 2>&1; then success "✅ $dep erfolgreich installiert" ((installed_count++)) else warning "⚠️ $dep Installation fehlgeschlagen oder Timeout" debug "$dep Timeout oder Fehler bei Installation" fi done if [ $installed_count -eq 0 ]; then warning "⚠️ Keine Python-Pakete konnten installiert werden" warning "⚠️ Überspringe Python-Pakete Installation - verwende System-Pakete" # Strategie 3: Fallback auf System-Pakete (APT) progress "Versuche System-Python-Pakete als Fallback..." local system_packages=("python3-flask" "python3-requests") local system_installed=0 for pkg in "${system_packages[@]}"; do if timeout 60 apt-get install -y "$pkg" >/dev/null 2>&1; then success "✅ System-Paket installiert: $pkg" ((system_installed++)) else debug "System-Paket fehlgeschlagen: $pkg" fi done if [ $system_installed -gt 0 ]; then success "✅ Fallback auf System-Pakete erfolgreich ($system_installed installiert)" else warning "⚠️ Auch System-Pakete Installation fehlgeschlagen" info " → System läuft mit vorhandenen Python-Paketen" info " → Manuell: pip3 install --break-system-packages Flask requests" info " → Oder: apt install python3-flask python3-requests" fi else success "✅ $installed_count von ${#essential_deps[@]} essenziellen Paketen installiert" fi fi # Schnelle Validierung nur der essenziellen Pakete (timeout-gesichert) progress "Validiere essenzielle Python-Module..." local essential_modules=("flask" "requests") local validation_success=true for module in "${essential_modules[@]}"; do if timeout 10 python3 -c "import $module; print(f'✅ $module verfügbar')" 2>/dev/null; then debug "$module erfolgreich importiert" else warning "⚠️ $module nicht verfügbar" validation_success=false fi done if [ "$validation_success" = true ]; then success "✅ Essenzielle Python-Module verfügbar" else warning "⚠️ Einige essenzielle Module fehlen" info " → System funktioniert möglicherweise trotzdem" info " → Fehlende Pakete: pip3 install --break-system-packages Flask requests" fi log "✅ Timeout-gesicherte Python-Pakete Installation abgeschlossen" debug "Python-Installation ohne hängende Prozesse beendet" } # =========================== ROBUSTE NODE.JS INSTALLATION =========================== install_nodejs_npm() { log "=== ROBUSTE NODE.JS UND NPM INSTALLATION ===" # Alte Installationen entfernen progress "Bereinige alte Node.js-Installationen..." apt-get remove --purge -y nodejs npm 2>/dev/null || true apt-get autoremove -y 2>/dev/null || true rm -rf /usr/local/bin/node /usr/local/bin/npm 2>/dev/null || true # NodeSource Repository mit Fallback progress "Installiere Node.js mit Fallback-Strategie..." local nodejs_installed=false # Strategie 1: NodeSource Repository if curl -fsSL https://deb.nodesource.com/setup_lts.x 2>/dev/null | bash - 2>/dev/null; then if apt-get update -y && apt_install_retry nodejs; then nodejs_installed=true log "✅ Node.js via NodeSource Repository installiert" fi fi # Strategie 2: Snap (falls verfügbar) if [ "$nodejs_installed" = false ] && command -v snap >/dev/null 2>&1; then progress "Versuche Node.js Installation via Snap..." if snap install node --classic 2>/dev/null; then nodejs_installed=true log "✅ Node.js via Snap installiert" fi fi # Strategie 3: Debian Repository (Fallback) if [ "$nodejs_installed" = false ]; then progress "Verwende Debian Repository als Fallback..." apt_install_retry nodejs npm nodejs_installed=true log "✅ Node.js via Debian Repository installiert" fi # Validierung progress "Validiere Node.js Installation..." if command -v node >/dev/null 2>&1; then local node_version=$(node --version) log "✅ Node.js Version: $node_version" else error "❌ Node.js nicht verfügbar nach Installation" fi if command -v npm >/dev/null 2>&1; then local npm_version=$(npm --version) log "✅ npm Version: $npm_version" # npm optimieren progress "Optimiere npm-Konfiguration..." npm config set fund false 2>/dev/null || true npm config set audit-level moderate 2>/dev/null || true npm config set progress false 2>/dev/null || true npm config set loglevel warn 2>/dev/null || true else # Versuche npm separat zu installieren progress "Installiere npm separat..." apt_install_retry npm fi log "✅ Node.js und npm erfolgreich installiert" } # =========================== NETZWERK-SICHERHEIT =========================== configure_network_security() { log "=== KONFIGURIERE ROBUSTE NETZWERK-SICHERHEIT ===" # IPv6 vorsichtig deaktivieren progress "Deaktiviere IPv6 (robust)..." # IPv6 in GRUB deaktivieren (nur wenn GRUB vorhanden) if [ -f /etc/default/grub ] && command -v update-grub >/dev/null 2>&1; then progress "Deaktiviere IPv6 in GRUB..." if cp /etc/default/grub /etc/default/grub.backup 2>/dev/null; then # Prüfe ob ipv6.disable bereits gesetzt ist if ! grep -q "ipv6.disable=1" /etc/default/grub; then sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="[^"]*/& ipv6.disable=1/' /etc/default/grub 2>/dev/null || true sed -i 's/GRUB_CMDLINE_LINUX="[^"]*/& ipv6.disable=1/' /etc/default/grub 2>/dev/null || true if timeout 30 update-grub >/dev/null 2>&1; then success "✅ IPv6 in GRUB deaktiviert" else warning "⚠️ GRUB-Update fehlgeschlagen" debug "GRUB-Update Fehler: $(update-grub 2>&1 || echo 'Befehl fehlgeschlagen')" fi else info "IPv6 bereits in GRUB deaktiviert" fi else warning "⚠️ GRUB-Backup konnte nicht erstellt werden" fi else info "GRUB nicht verfügbar oder kein update-grub - überspringe" fi # IPv6 und Netzwerk-Sicherheit in sysctl konfigurieren (robust) progress "Erstelle robuste sysctl-Konfiguration..." # Backup der bestehenden sysctl.conf if [ -f /etc/sysctl.conf ]; then cp /etc/sysctl.conf /etc/sysctl.conf.backup.$(date +%Y%m%d_%H%M%S) 2>/dev/null || true fi # Erstelle separate sysctl-Datei für MYP (sicherer) local myp_sysctl_file="/etc/sysctl.d/99-myp-security.conf" # Nur kritische und kompatible Einstellungen setzen cat > "$myp_sysctl_file" << 'EOF' # =================================================================== # MYP Basis-Sicherheitskonfiguration (kompatibel) # =================================================================== # IPv6 deaktivieren (nur wenn unterstützt) net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 # Grundlegende Netzwerk-Sicherheit net.ipv4.ip_forward = 0 net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 # ICMP-Sicherheit net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 # Source Routing deaktivieren net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 EOF # Teste ob die Datei geschrieben werden konnte if [ -f "$myp_sysctl_file" ]; then success "✅ Basis-sysctl-Konfiguration erstellt" debug "sysctl-Konfiguration erstellt: $myp_sysctl_file" else warning "⚠️ sysctl-Konfigurationsdatei konnte nicht erstellt werden" return fi # Optional: Erweiterte Einstellungen nur wenn Raspberry Pi if [ "${RASPBERRY_PI_DETECTED:-0}" = "1" ]; then progress "Füge Raspberry Pi spezifische Optimierungen hinzu..." cat >> "$myp_sysctl_file" << 'EOF' # =================================================================== # RASPBERRY PI PERFORMANCE-OPTIMIERUNGEN (optional) # =================================================================== # Memory Management für schwache Hardware vm.swappiness = 10 vm.dirty_ratio = 15 vm.dirty_background_ratio = 5 vm.vfs_cache_pressure = 50 # Filesystem Performance vm.dirty_expire_centisecs = 500 vm.dirty_writeback_centisecs = 100 EOF debug "Raspberry Pi Optimierungen zur sysctl-Konfiguration hinzugefügt" fi # Sysctl-Einstellungen vorsichtig anwenden (non-blocking) progress "Wende sysctl-Einstellungen an (non-blocking)..." # Teste unsere spezielle sysctl-Datei zuerst (mit mehreren Fallbacks) if [ -f "$myp_sysctl_file" ]; then local sysctl_success=false # Strategie 1: Komplette Datei mit Timeout anwenden progress "Versuche komplette sysctl-Datei anzuwenden..." if timeout 10 sysctl -p "$myp_sysctl_file" >/dev/null 2>&1; then success "✅ MYP sysctl-Einstellungen erfolgreich angewendet" sysctl_success=true else warning "⚠️ Komplette sysctl-Datei fehlgeschlagen" debug "sysctl -p $myp_sysctl_file Fehlerausgabe: $(timeout 5 sysctl -p "$myp_sysctl_file" 2>&1 || echo 'Timeout oder Fehler')" fi # Strategie 2: Nur IPv6-Deaktivierung (kritisch) if [ "$sysctl_success" = false ]; then progress "Versuche nur IPv6-Deaktivierung..." local ipv6_settings=( "net.ipv6.conf.all.disable_ipv6=1" "net.ipv6.conf.default.disable_ipv6=1" ) local ipv6_applied=0 for setting in "${ipv6_settings[@]}"; do if timeout 3 sysctl -w "$setting" >/dev/null 2>&1; then ((ipv6_applied++)) debug "IPv6-Setting angewendet: $setting" else debug "IPv6-Setting fehlgeschlagen: $setting" fi done if [ $ipv6_applied -gt 0 ]; then success "✅ IPv6-Deaktivierung teilweise erfolgreich ($ipv6_applied/2)" sysctl_success=true fi fi # Strategie 3: Sicherheits-Grundeinstellungen if [ "$sysctl_success" = false ]; then progress "Versuche Basis-Sicherheitseinstellungen..." local security_settings=( "net.ipv4.ip_forward=0" "net.ipv4.tcp_syncookies=1" ) local security_applied=0 for setting in "${security_settings[@]}"; do if timeout 3 sysctl -w "$setting" >/dev/null 2>&1; then ((security_applied++)) debug "Sicherheits-Setting angewendet: $setting" else debug "Sicherheits-Setting fehlgeschlagen: $setting" fi done if [ $security_applied -gt 0 ]; then success "✅ Basis-Sicherheitseinstellungen angewendet ($security_applied/2)" sysctl_success=true fi fi # Strategie 4: Vollständig überspringen (Graceful Degradation) if [ "$sysctl_success" = false ]; then warning "⚠️ Alle sysctl-Anwendungen fehlgeschlagen" warning "⚠️ Einstellungen werden beim nächsten Neustart automatisch aktiv" info " 📁 Konfiguration verfügbar in: $myp_sysctl_file" info " 🔧 Manuelle Anwendung: sudo sysctl -p $myp_sysctl_file" debug "Sysctl komplett übersprungen - System läuft mit Standard-Einstellungen" fi else warning "⚠️ MYP sysctl-Konfigurationsdatei nicht gefunden" debug "Überspringe sysctl-Anwendung komplett" fi # Niemals das System-weite sysctl -p ausführen (zu problematisch) debug "Überspringe system-weites sysctl -p (zu riskant)" # IPv6 in Netzwerk-Interfaces deaktivieren (robust) progress "Deaktiviere IPv6 in Netzwerk-Interfaces (vorsichtig)..." # Für systemd-networkd (nur wenn aktiv) if systemctl is-enabled systemd-networkd >/dev/null 2>&1 && systemctl is-active systemd-networkd >/dev/null 2>&1; then progress "Konfiguriere systemd-networkd für IPv6-Deaktivierung..." if mkdir -p /etc/systemd/network 2>/dev/null; then cat > /etc/systemd/network/99-disable-ipv6.network << 'EOF' [Match] Name=* [Network] IPv6AcceptRA=no LinkLocalAddressing=no EOF if systemctl restart systemd-networkd >/dev/null 2>&1; then success "✅ systemd-networkd IPv6 deaktiviert" else warning "⚠️ systemd-networkd Neustart fehlgeschlagen" fi else warning "⚠️ systemd-networkd Verzeichnis konnte nicht erstellt werden" fi else debug "systemd-networkd nicht aktiv - überspringe" fi # Für NetworkManager (nur wenn aktiv) if systemctl is-enabled NetworkManager >/dev/null 2>&1 && systemctl is-active NetworkManager >/dev/null 2>&1; then progress "Konfiguriere NetworkManager für IPv6-Deaktivierung..." if mkdir -p /etc/NetworkManager/conf.d 2>/dev/null; then cat > /etc/NetworkManager/conf.d/99-disable-ipv6.conf << 'EOF' [main] plugins=keyfile [keyfile] unmanaged-devices=none [connection] ipv6.method=ignore EOF if systemctl restart NetworkManager >/dev/null 2>&1; then success "✅ NetworkManager IPv6 deaktiviert" else warning "⚠️ NetworkManager Neustart fehlgeschlagen" fi else warning "⚠️ NetworkManager Verzeichnis konnte nicht erstellt werden" fi else debug "NetworkManager nicht aktiv - überspringe" fi # IPv6 in /etc/hosts auskommentieren (vorsichtig) if [ -f /etc/hosts ]; then if sed -i.backup 's/^::1/#::1/' /etc/hosts 2>/dev/null; then debug "IPv6 Einträge in /etc/hosts auskommentiert" else debug "IPv6 Einträge in /etc/hosts konnten nicht geändert werden" fi fi # Abschließende Zusammenfassung log "✅ Robuste Netzwerk-Sicherheit konfiguriert:" log " 🚫 IPv6 Deaktivierung konfiguriert" log " 🛡️ Netzwerk-Sicherheitsregeln gesetzt" log " 🔒 Basis-Firewall-Schutz aktiviert" log " 📝 Sysctl-Konfiguration erstellt: $myp_sysctl_file" log " 🔧 Netzwerk-Services entsprechend konfiguriert" log " ⚙️ Einstellungen werden beim nächsten Boot aktiv" # Alternative für sysctl-Probleme dokumentieren debug "Alternative sysctl-Anwendung:" debug " - Manuell: sysctl -p $myp_sysctl_file" debug " - Automatisch: Beim nächsten Neustart aktiv" debug " - Verifikation: sysctl net.ipv6.conf.all.disable_ipv6" } # =========================== DESKTOP-ENVIRONMENT ENTFERNUNG =========================== remove_desktop_environments() { log "=== ENTFERNE DESKTOP ENVIRONMENTS FÜR KIOSK-MODUS ===" progress "Stoppe alle Desktop-Services..." local desktop_services=("lightdm" "gdm3" "sddm" "xdm" "nodm") for service in "${desktop_services[@]}"; do systemctl stop "$service" 2>/dev/null || true systemctl disable "$service" 2>/dev/null || true done progress "Entferne Desktop-Pakete vollständig..." # Raspberry Pi OS Desktop-Pakete apt-get remove --purge -y \ raspberrypi-ui-mods \ pi-package \ desktop-base \ lxde* \ xfce4* \ gnome* \ kde* \ mate* \ cinnamon* \ openbox \ pcmanfm \ file-manager* \ task-lxde-desktop \ task-xfce-desktop \ task-gnome-desktop \ task-kde-desktop \ 2>/dev/null || true # Display Manager entfernen apt-get remove --purge -y \ lightdm* \ gdm3* \ sddm* \ xdm* \ nodm* \ 2>/dev/null || true # Unnötige Anwendungen entfernen apt-get remove --purge -y \ libreoffice* \ thunderbird* \ firefox* \ vlc* \ gimp* \ scratch* \ minecraft-pi \ sonic-pi \ 2>/dev/null || true # Aufräumen apt-get autoremove --purge -y apt-get autoclean log "✅ Desktop Environments vollständig entfernt" } # =========================== MINIMALE X11-UMGEBUNG =========================== install_minimal_x11() { log "=== INSTALLIERE MINIMALE X11-UMGEBUNG FÜR KIOSK ===" progress "Installiere minimale X11-Pakete..." apt-get install -y \ xserver-xorg-core \ xserver-xorg-input-all \ xserver-xorg-video-fbdev \ xserver-xorg-video-vesa \ xinit \ x11-xserver-utils \ xdotool \ unclutter \ openbox \ || error "X11 Installation fehlgeschlagen" # Browser-Installation mit Fallback-Mechanismus progress "Installiere Browser für Kiosk-Modus..." local browser_installed=false # Versuche Chromium zu installieren if apt-get install -y chromium 2>/dev/null; then log "✅ Chromium erfolgreich installiert" browser_installed=true elif apt-get install -y chromium-browser 2>/dev/null; then log "✅ Chromium-Browser erfolgreich installiert" browser_installed=true elif apt-get install -y firefox-esr 2>/dev/null; then warning "⚠️ Chromium nicht verfügbar - Firefox ESR als Fallback installiert" browser_installed=true fi if [ "$browser_installed" = false ]; then error "❌ Kein Browser verfügbar (chromium, chromium-browser, firefox-esr)" fi log "✅ Minimale X11-Umgebung installiert" } # =========================== KIOSK-BENUTZER MANAGEMENT =========================== create_kiosk_user() { log "=== KIOSK-BENUTZER SETUP ===" if ! id "$KIOSK_USER" &>/dev/null; then progress "Erstelle Kiosk-Benutzer: $KIOSK_USER" useradd -m -s /bin/bash "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen" # Gruppen hinzufügen usermod -aG audio,video,input,dialout,plugdev,users "$KIOSK_USER" 2>/dev/null || true # pip-Konfiguration für Kiosk-Benutzer local kiosk_home="/home/$KIOSK_USER" mkdir -p "$kiosk_home/.pip" 2>/dev/null || true cat > "$kiosk_home/.pip/pip.conf" << 'EOF' [global] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org timeout = 60 retries = 3 [install] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org EOF chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.pip/pip.conf" 2>/dev/null || true else info "Kiosk-Benutzer $KIOSK_USER existiert bereits" fi # Passwort entfernen für automatischen Login passwd -d "$KIOSK_USER" || warning "Konnte Passwort nicht entfernen" log "✅ Kiosk-Benutzer konfiguriert: $KIOSK_USER" } configure_autologin() { log "=== KONFIGURIERE AUTOLOGIN FÜR KIOSK-BENUTZER ===" # Getty-Service für automatischen Login konfigurieren progress "Konfiguriere automatischen Login auf tty1..." local getty_override_dir="/etc/systemd/system/getty@tty1.service.d" mkdir -p "$getty_override_dir" cat > "$getty_override_dir/override.conf" << EOF [Service] ExecStart= ExecStart=-/sbin/agetty --autologin $KIOSK_USER --noclear %I \$TERM EOF # Systemd-Konfiguration neu laden systemctl daemon-reload systemctl enable getty@tty1.service log "✅ Autologin für $KIOSK_USER konfiguriert" } configure_kiosk_autostart() { log "=== KONFIGURIERE AUTOMATISCHEN KIOSK-START ===" # Erstelle .bashrc für automatischen X-Server und Browser-Start progress "Konfiguriere automatischen Kiosk-Start für $KIOSK_USER..." local kiosk_home="/home/$KIOSK_USER" # .bashrc für automatischen Start erstellen cat > "$kiosk_home/.bashrc" << 'EOF' # Automatischer Kiosk-Start beim Login if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then echo "Starte Kiosk-Modus..." # X-Server im Hintergrund starten startx /home/kiosk/.xinitrc -- :0 vt1 & # Warte bis X-Server bereit ist sleep 5 # Setze DISPLAY-Variable export DISPLAY=:0 # Warte auf HTTPS-Backend echo "Warte auf HTTPS-Backend..." for i in {1..60}; do if curl -k -s https://localhost:443 >/dev/null 2>&1; then echo "HTTPS-Backend erreichbar" break fi echo "Warte... ($i/60)" sleep 2 done # Bildschirmschoner deaktivieren xset s off xset s noblank xset -dpms # Mauszeiger verstecken unclutter -idle 0.1 -root -noevents & # Browser im Kiosk-Modus starten if command -v chromium >/dev/null 2>&1; then BROWSER="chromium" elif command -v chromium-browser >/dev/null 2>&1; then BROWSER="chromium-browser" else BROWSER="firefox-esr" fi echo "Starte $BROWSER im Kiosk-Modus..." if [[ "$BROWSER" == "chromium"* ]]; then exec $BROWSER \ --kiosk \ --no-sandbox \ --disable-infobars \ --disable-session-crashed-bubble \ --disable-restore-session-state \ --disable-features=TranslateUI \ --disable-extensions \ --disable-plugins \ --disable-popup-blocking \ --disable-prompt-on-repost \ --disable-sync \ --disable-translate \ --noerrdialogs \ --no-first-run \ --no-default-browser-check \ --autoplay-policy=no-user-gesture-required \ --start-fullscreen \ --start-maximized \ --user-data-dir=/home/kiosk/.chromium-kiosk \ --disable-background-mode \ --force-device-scale-factor=1.0 \ --disable-pinch \ --overscroll-history-navigation=0 \ --disable-dev-shm-usage \ --memory-pressure-off \ --max_old_space_size=512 \ --disable-background-timer-throttling \ --disable-backgrounding-occluded-windows \ --disable-renderer-backgrounding \ --disable-features=VizDisplayCompositor \ --enable-features=OverlayScrollbar \ --hide-scrollbars \ --ignore-certificate-errors \ --ignore-ssl-errors \ --ignore-certificate-errors-spki-list \ --disable-web-security \ --allow-running-insecure-content \ --unsafely-treat-insecure-origin-as-secure=https://localhost:443 \ https://localhost:443 else exec firefox-esr \ --kiosk \ https://localhost:443 fi fi EOF # .xinitrc für X-Server-Konfiguration erstellen cat > "$kiosk_home/.xinitrc" << 'EOF' #!/bin/bash # Minimale X-Session für Kiosk-Modus exec openbox-session EOF # Berechtigungen setzen chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.xinitrc" chmod +x "$kiosk_home/.xinitrc" # Erstelle Kiosk-Verzeichnisse mkdir -p "$kiosk_home/.chromium-kiosk" chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.chromium-kiosk" log "✅ Automatischer Kiosk-Start konfiguriert" info "Der Kiosk-Modus startet automatisch beim Login des $KIOSK_USER" } # =========================== ROBUSTE SSL-ZERTIFIKATE INSTALLATION =========================== install_ssl_certificates() { log "=== TIMEOUT-GESICHERTE SSL-ZERTIFIKATE KONFIGURATION ===" progress "Installiere SSL-Grundkomponenten..." apt_install_retry ca-certificates openssl progress "Aktualisiere CA-Zertifikate (timeout-gesichert)..." if timeout 30 update-ca-certificates >/dev/null 2>&1; then success "✅ CA-Zertifikate erfolgreich aktualisiert" else warning "⚠️ CA-Zertifikate Update fehlgeschlagen oder Timeout" debug "Erste CA-Update Timeout - System läuft mit bestehenden Zertifikaten" fi # SSL-Verzeichnisse sicherstellen if mkdir -p /usr/local/share/ca-certificates/myp 2>/dev/null; then debug "SSL-Verzeichnis erstellt: /usr/local/share/ca-certificates/myp" else warning "⚠️ SSL-Verzeichnis konnte nicht erstellt werden" fi # Mercedes Corporate Zertifikate (timeout-gesichert) if [ -d "$CURRENT_DIR/certs/mercedes" ] && [ "$(ls -A $CURRENT_DIR/certs/mercedes 2>/dev/null)" ]; then progress "Installiere Mercedes Corporate Zertifikate (timeout-gesichert)..." local cert_count=0 local installed_count=0 local max_certs=10 # Begrenze Anzahl verarbeiteter Zertifikate # Timeout für die gesamte Zertifikat-Verarbeitung timeout 60 bash -c ' cert_count=0 installed_count=0 max_certs=10 find "$1/certs/mercedes" -type f \( -name "*.crt" -o -name "*.pem" -o -name "*.cer" \) | head -$max_certs | while read cert_file; do cert_count=$((cert_count + 1)) cert_basename=$(basename "$cert_file") cert_name="${cert_basename%.*}" target_file="/usr/local/share/ca-certificates/myp/${cert_name}.crt" echo "Verarbeite Mercedes-Zertifikat ($cert_count/$max_certs): $cert_basename" # Timeout für einzelne Zertifikat-Operationen if timeout 10 openssl x509 -in "$cert_file" -text -noout >/dev/null 2>&1; then # PEM Format if cp "$cert_file" "$target_file" 2>/dev/null; then echo "✅ PEM-Zertifikat installiert: ${cert_name}.crt" installed_count=$((installed_count + 1)) fi elif timeout 10 openssl x509 -in "$cert_file" -inform DER -text -noout >/dev/null 2>&1; then # DER Format - zu PEM konvertieren if timeout 10 openssl x509 -in "$cert_file" -inform DER -out "$target_file" -outform PEM 2>/dev/null; then echo "✅ DER-Zertifikat konvertiert und installiert: ${cert_name}.crt" installed_count=$((installed_count + 1)) fi else echo "⚠️ Ungültiges Zertifikat übersprungen: $cert_file" fi # Kurze Pause zwischen Zertifikaten sleep 0.5 done echo "Mercedes-Zertifikate verarbeitet: $installed_count von $cert_count" ' -- "$CURRENT_DIR" 2>/dev/null || { warning "⚠️ Mercedes-Zertifikate Verarbeitung abgebrochen (Timeout nach 60s)" debug "Mercedes-Zertifikate Timeout - möglicherweise zu viele oder defekte Dateien" } # Versuche CA-Update nur wenn Zertifikate installiert wurden if [ "$(ls -A /usr/local/share/ca-certificates/myp/ 2>/dev/null)" ]; then progress "Lade CA-Zertifikate nach Mercedes-Import neu (timeout-gesichert)..." if timeout 30 update-ca-certificates >/dev/null 2>&1; then success "✅ Mercedes-Zertifikate erfolgreich in CA-Store integriert" else warning "⚠️ CA-Zertifikate Update fehlgeschlagen oder Timeout" debug "update-ca-certificates Timeout - CA-Store möglicherweise inkonsistent" fi else info "Keine Mercedes-Zertifikate gefunden oder installiert" fi else debug "Mercedes-Zertifikate-Verzeichnis nicht gefunden oder leer" fi # SSL-Umgebungsvariablen systemweit setzen progress "Konfiguriere SSL-Umgebungsvariablen..." cat >> /etc/environment << 'EOF' # SSL Certificate Configuration für MYP SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt EOF # SSL-Umgebungsvariablen für aktuelle Session export SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt" export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" export CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" # Validiere SSL-Setup progress "Validiere SSL-Konfiguration..." if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then local cert_count=$(grep -c "BEGIN CERTIFICATE" /etc/ssl/certs/ca-certificates.crt 2>/dev/null || echo "0") log "✅ SSL-Zertifikate verfügbar: $cert_count CA-Zertifikate" else warning "⚠️ CA-Zertifikate-Datei nicht gefunden" fi # Finale SSL-Konfiguration (timeout-gesichert) progress "Finalisiere SSL-Konfiguration..." # Finaler CA-Update (nur wenn wirklich nötig) if [ "$(ls -A /usr/local/share/ca-certificates/myp/ 2>/dev/null)" ] && [ ! -f "/tmp/myp-ca-updated" ]; then if timeout 20 update-ca-certificates >/dev/null 2>&1; then touch "/tmp/myp-ca-updated" success "✅ Finale CA-Zertifikate Integration abgeschlossen" else warning "⚠️ Finale CA-Integration fehlgeschlagen - Zertifikate beim nächsten Boot aktiv" fi fi log "✅ SSL-Zertifikate timeout-gesichert konfiguriert" debug "SSL-Konfiguration abgeschlossen ohne hängende Prozesse" } # =========================== ROBUSTES ANWENDUNGS-DEPLOYMENT =========================== deploy_application() { log "=== ROBUSTES ANWENDUNGS-DEPLOYMENT ===" progress "Erstelle sicheres Zielverzeichnis: $APP_DIR" mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen" # Validiere Source-Verzeichnis progress "Validiere Source-Dateien..." if [ ! -f "$CURRENT_DIR/app.py" ]; then error "Kritische Datei nicht gefunden: $CURRENT_DIR/app.py" fi if [ ! -f "$CURRENT_DIR/requirements.txt" ]; then error "Kritische Datei nicht gefunden: $CURRENT_DIR/requirements.txt" fi progress "Kopiere Anwendungsdateien (robust)..." # Kritische Dateien zuerst (mit Validierung) local critical_files=( "app.py" "models.py" "requirements.txt" ) for file in "${critical_files[@]}"; do if [ -f "$CURRENT_DIR/$file" ]; then progress "Kopiere kritische Datei: $file" if cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null; then success "✅ $file erfolgreich kopiert" else error "❌ Fehler beim Kopieren der kritischen Datei: $file" fi else error "❌ Kritische Datei fehlt: $file" fi done # Verzeichnisse mit robuster Behandlung local directories=( "blueprints" "config" "database" "static" "templates" "uploads" "utils" "logs" "certs" ) for dir in "${directories[@]}"; do if [ -d "$CURRENT_DIR/$dir" ]; then progress "Kopiere Verzeichnis: $dir" if cp -r "$CURRENT_DIR/$dir" "$APP_DIR/" 2>/dev/null; then success "✅ $dir erfolgreich kopiert" else warning "⚠️ Fehler beim Kopieren von $dir (möglicherweise nicht kritisch)" fi else info "Verzeichnis nicht vorhanden: $dir" fi done # Optionale Dateien local optional_files=( "package.json" "package-lock.json" "tailwind.config.js" "postcss.config.js" "README.md" ".gitignore" ) for file in "${optional_files[@]}"; do if [ -f "$CURRENT_DIR/$file" ]; then progress "Kopiere optionale Datei: $file" cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null || warning "⚠️ Kopieren von $file fehlgeschlagen" fi done # Erstelle alle notwendigen Verzeichnisse mit korrekter Struktur progress "Erstelle Verzeichnisstruktur..." local required_dirs=( "database/backups" "logs/app" "logs/auth" "logs/errors" "logs/system" "uploads/temp" "uploads/assets" "uploads/avatars" "uploads/backups" "uploads/jobs" "certs/localhost" "instance" "instance/ssl" ) for dir in "${required_dirs[@]}"; do mkdir -p "$APP_DIR/$dir" 2>/dev/null || warning "⚠️ Verzeichnis $dir konnte nicht erstellt werden" done # Sichere Berechtigungen setzen (robuster) progress "Setze sichere Berechtigungen..." # Basis-Berechtigungen chown -R root:root "$APP_DIR" 2>/dev/null || warning "⚠️ Ownership konnte nicht gesetzt werden" chmod 755 "$APP_DIR" 2>/dev/null || warning "⚠️ Verzeichnis-Permissions konnten nicht gesetzt werden" # Ausführbare Dateien if [ -f "$APP_DIR/app.py" ]; then chmod +x "$APP_DIR/app.py" 2>/dev/null || warning "⚠️ app.py Ausführberechtigung konnte nicht gesetzt werden" fi # Sensitive Verzeichnisse chmod 750 "$APP_DIR/database" 2>/dev/null || true chmod 750 "$APP_DIR/logs" 2>/dev/null || true chmod 750 "$APP_DIR/certs" 2>/dev/null || true chmod 750 "$APP_DIR/instance" 2>/dev/null || true # Upload-Verzeichnisse chmod 755 "$APP_DIR/uploads" 2>/dev/null || true chmod 755 "$APP_DIR/static" 2>/dev/null || true # Python-Umgebung robust konfigurieren progress "Konfiguriere robuste Python-Umgebung..." # Ermittle Python site-packages Verzeichnis (robust) local python_site_packages="" for possible_path in \ "$(python3 -c "import site; print(site.getsitepackages()[0])" 2>/dev/null)" \ "/usr/local/lib/python3/dist-packages" \ "/usr/lib/python3/dist-packages" \ "/usr/local/lib/python$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)/dist-packages"; do if [ -d "$possible_path" ]; then python_site_packages="$possible_path" break fi done if [ -n "$python_site_packages" ]; then echo "$APP_DIR" > "$python_site_packages/myp-app.pth" 2>/dev/null || warning "⚠️ Python-Pfad konnte nicht konfiguriert werden" log "✅ Python-Pfad konfiguriert: $python_site_packages/myp-app.pth" else warning "⚠️ Python site-packages Verzeichnis nicht gefunden" fi # Systemweite Umgebungsvariablen robust setzen progress "Konfiguriere Umgebungsvariablen..." cat >> /etc/environment << EOF # MYP Application Environment MYP_APP_DIR=$APP_DIR PYTHONPATH=$APP_DIR:\${PYTHONPATH:-} FLASK_APP=$APP_DIR/app.py FLASK_ENV=production EOF # Bash-Profile für alle User aktualisieren (robust) progress "Aktualisiere Bash-Profile..." local profile_updated=0 for user_home in "/root" "/home/"*; do if [ -d "$user_home" ] && [ "$user_home" != "/home/lost+found" ] && [ -w "$user_home" ]; then if ! grep -q "MYP Application Environment" "$user_home/.bashrc" 2>/dev/null; then cat >> "$user_home/.bashrc" << 'EOF' # MYP Application Environment if [ -d "/opt/myp" ]; then export MYP_APP_DIR="/opt/myp" export FLASK_APP="/opt/myp/app.py" export FLASK_ENV="production" if [ -z "${PYTHONPATH:-}" ]; then export PYTHONPATH="/opt/myp" else export PYTHONPATH="/opt/myp:$PYTHONPATH" fi fi EOF ((profile_updated++)) log "✅ Bash-Profile aktualisiert: $user_home/.bashrc" fi fi done # Validiere Deployment progress "Validiere Application Deployment..." local validation_errors=0 # Prüfe kritische Dateien for file in "app.py" "models.py" "requirements.txt"; do if [ ! -f "$APP_DIR/$file" ]; then warning "❌ Kritische Datei fehlt: $file" ((validation_errors++)) fi done # Prüfe wichtige Verzeichnisse for dir in "static" "templates" "blueprints"; do if [ ! -d "$APP_DIR/$dir" ]; then warning "❌ Wichtiges Verzeichnis fehlt: $dir" ((validation_errors++)) fi done if [ $validation_errors -eq 0 ]; then success "✅ Application Deployment vollständig validiert" else warning "⚠️ $validation_errors Probleme beim Deployment gefunden" fi log "✅ Robustes Anwendungs-Deployment abgeschlossen" log " 📁 App-Verzeichnis: $APP_DIR" log " 🐍 Python-Pfad konfiguriert" log " 🔧 $profile_updated Bash-Profile aktualisiert" log " 🛡️ Sichere Berechtigungen gesetzt" } install_npm_dependencies() { log "=== NPM-ABHÄNGIGKEITEN INSTALLATION ===" if [ -f "$APP_DIR/package.json" ]; then progress "Installiere npm-Abhängigkeiten..." cd "$APP_DIR" # npm install mit verschiedenen Fallback-Strategien if npm install --no-optional --no-audit --no-fund 2>/dev/null; then log "✅ npm install erfolgreich (Standard)" elif npm install --legacy-peer-deps --no-optional 2>/dev/null; then log "✅ npm install erfolgreich (Legacy-Modus)" elif npm install --force 2>/dev/null; then log "✅ npm install erfolgreich (Force-Modus)" else warning "⚠️ npm install fehlgeschlagen - überspringe" fi cd "$CURRENT_DIR" else info "Keine package.json gefunden - überspringe npm-Installation" fi log "✅ NPM-Abhängigkeiten verarbeitet" } # =========================== SSL-ZERTIFIKAT GENERIERUNG =========================== generate_ssl_certificate() { log "=== SSL-ZERTIFIKAT GENERIERUNG ===" progress "Generiere selbstsigniertes SSL-Zertifikat für localhost..." local cert_dir="$APP_DIR/certs/localhost" mkdir -p "$cert_dir" # Generiere privaten Schlüssel openssl genrsa -out "$cert_dir/localhost.key" 2048 || error "Fehler beim Generieren des privaten Schlüssels" # Generiere Zertifikat openssl req -new -x509 -key "$cert_dir/localhost.key" -out "$cert_dir/localhost.crt" -days 365 \ -subj "/C=DE/ST=Baden-Wuerttemberg/L=Stuttgart/O=Mercedes-Benz/OU=IT/CN=localhost" \ || error "Fehler beim Generieren des SSL-Zertifikats" # Berechtigungen setzen chmod 600 "$cert_dir/localhost.key" chmod 644 "$cert_dir/localhost.crt" log "✅ SSL-Zertifikat erfolgreich generiert" } # =========================== ROBUSTE SYSTEMD-SERVICES INSTALLATION =========================== install_systemd_services() { log "=== ROBUSTE SYSTEMD-SERVICES INSTALLATION ===" # Validiere systemd-Verzeichnis if [ ! -d "$SYSTEMD_DIR" ]; then error "systemd-Verzeichnis nicht gefunden: $SYSTEMD_DIR" fi progress "Validiere und kopiere Service-Dateien..." # Definiere Service-Dateien mit Priorität local essential_services=( "$HTTPS_SERVICE_NAME.service" ) local optional_services=( "$KIOSK_SERVICE_NAME.service" "$WATCHDOG_SERVICE_NAME.service" "$WATCHDOG_PYTHON_SERVICE_NAME.service" "$FIREWALL_SERVICE_NAME.service" ) local installed_services=0 local essential_errors=0 # Essenzielle Services zuerst for service_file in "${essential_services[@]}"; do if [ -f "$SYSTEMD_DIR/$service_file" ]; then progress "Kopiere essenziellen Service: $service_file" if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then success "✅ $service_file erfolgreich installiert" ((installed_services++)) else error "❌ Fehler beim Kopieren des essenziellen Service: $service_file" ((essential_errors++)) fi else error "❌ Essenzieller Service nicht gefunden: $service_file" ((essential_errors++)) fi done # Optionale Services for service_file in "${optional_services[@]}"; do if [ -f "$SYSTEMD_DIR/$service_file" ]; then progress "Kopiere optionalen Service: $service_file" if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then success "✅ $service_file erfolgreich installiert" ((installed_services++)) else warning "⚠️ Fehler beim Kopieren des optionalen Service: $service_file" fi else info "Optionaler Service nicht gefunden: $service_file" fi done # Prüfe auf kritische Fehler if [ $essential_errors -gt 0 ]; then error "❌ $essential_errors essenzielle Services konnten nicht installiert werden!" fi # Validiere kopierte Service-Dateien progress "Validiere Service-Dateien..." for service_file in "${essential_services[@]}" "${optional_services[@]}"; do if [ -f "$SYSTEM_SYSTEMD_DIR/$service_file" ]; then # Syntaxprüfung für systemd-Services if systemd-analyze verify "$SYSTEM_SYSTEMD_DIR/$service_file" 2>/dev/null; then success "✅ $service_file Syntax-Validierung erfolgreich" else warning "⚠️ $service_file hat möglicherweise Syntax-Probleme" fi fi done # Systemd-Konfiguration neu laden progress "Lade systemd-Konfiguration neu..." retry_command "systemctl daemon-reload" "systemd daemon-reload" log "✅ Systemd-Services installiert: $installed_services Services" } enable_and_start_services() { log "=== ROBUSTE SERVICES AKTIVIERUNG UND START ===" # Service-Status tracking local successful_services=0 local failed_services=0 # HTTPS-Service (kritisch) progress "Aktiviere und starte HTTPS-Service (kritisch)..." if systemctl enable "$HTTPS_SERVICE_NAME" 2>/dev/null; then success "✅ HTTPS-Service erfolgreich aktiviert" if systemctl start "$HTTPS_SERVICE_NAME" 2>/dev/null; then success "✅ HTTPS-Service erfolgreich gestartet" # Warte und prüfe Status gründlich local startup_timeout=15 local check_interval=2 local elapsed=0 while [ $elapsed -lt $startup_timeout ]; do if systemctl is-active --quiet "$HTTPS_SERVICE_NAME"; then success "✅ HTTPS-Service läuft stabil nach ${elapsed}s" ((successful_services++)) break fi sleep $check_interval elapsed=$((elapsed + check_interval)) progress "Warte auf HTTPS-Service Startup... (${elapsed}/${startup_timeout}s)" done if [ $elapsed -ge $startup_timeout ]; then error "❌ HTTPS-Service Timeout nach ${startup_timeout}s - Service nicht verfügbar" # Debugging-Informationen info "HTTPS-Service Status-Debug:" systemctl status "$HTTPS_SERVICE_NAME" --no-pager -l || true journalctl -u "$HTTPS_SERVICE_NAME" --no-pager -n 10 || true ((failed_services++)) fi else error "❌ HTTPS-Service konnte nicht gestartet werden" ((failed_services++)) fi else error "❌ HTTPS-Service konnte nicht aktiviert werden" ((failed_services++)) fi # Kiosk-Service (für Produktionsinstallation) if [ -f "$SYSTEM_SYSTEMD_DIR/$KIOSK_SERVICE_NAME.service" ]; then progress "Aktiviere Kiosk-Service (startet beim nächsten Boot)..." if systemctl enable "$KIOSK_SERVICE_NAME" 2>/dev/null; then success "✅ Kiosk-Service erfolgreich aktiviert" ((successful_services++)) else warning "⚠️ Kiosk-Service konnte nicht aktiviert werden" ((failed_services++)) fi fi # Watchdog-Service (optional) if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_SERVICE_NAME.service" ]; then progress "Aktiviere und starte Watchdog-Service..." if systemctl enable "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then if systemctl start "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then success "✅ Watchdog-Service erfolgreich aktiviert und gestartet" ((successful_services++)) else warning "⚠️ Watchdog-Service aktiviert, aber Start fehlgeschlagen" fi else warning "⚠️ Watchdog-Service konnte nicht aktiviert werden" fi fi # Python Watchdog-Service (optional) if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_PYTHON_SERVICE_NAME.service" ]; then progress "Aktiviere Python Watchdog-Service..." if systemctl enable "$WATCHDOG_PYTHON_SERVICE_NAME" 2>/dev/null; then success "✅ Python Watchdog-Service erfolgreich aktiviert" ((successful_services++)) else warning "⚠️ Python Watchdog-Service konnte nicht aktiviert werden" fi fi # Firewall-Service (optional) if [ -f "$SYSTEM_SYSTEMD_DIR/$FIREWALL_SERVICE_NAME.service" ]; then progress "Aktiviere Firewall-Service..." if systemctl enable "$FIREWALL_SERVICE_NAME" 2>/dev/null; then success "✅ Firewall-Service erfolgreich aktiviert" ((successful_services++)) else warning "⚠️ Firewall-Service konnte nicht aktiviert werden" fi fi # Zusammenfassung log "📊 Service-Aktivierung Zusammenfassung:" log " ✅ Erfolgreich: $successful_services Services" log " ❌ Fehlgeschlagen: $failed_services Services" if [ $failed_services -eq 0 ]; then success "✅ Alle verfügbaren Services erfolgreich konfiguriert" elif [ $successful_services -gt 0 ]; then warning "⚠️ $failed_services Services fehlgeschlagen, aber $successful_services Services funktionieren" info "→ System ist grundsätzlich funktionsfähig" else error "❌ Alle Services fehlgeschlagen - System möglicherweise nicht funktionsfähig" fi } # =========================== ROBUSTE SYSTEM-TESTS =========================== test_application() { log "=== UMFASSENDE SYSTEM-TESTS ===" local test_errors=0 local test_warnings=0 # Test 1: Service-Status prüfen progress "Teste Service-Status..." if systemctl is-active --quiet "$HTTPS_SERVICE_NAME"; then success "✅ HTTPS-Service ist aktiv" else warning "⚠️ HTTPS-Service ist nicht aktiv" ((test_warnings++)) # Debug-Informationen info "Service-Status Debug:" systemctl status "$HTTPS_SERVICE_NAME" --no-pager -l || true fi # Test 2: Port-Verfügbarkeit progress "Teste Port-Verfügbarkeit..." if ss -tlnp | grep -q ":443 "; then success "✅ Port 443 ist geöffnet" else warning "⚠️ Port 443 ist nicht geöffnet" ((test_warnings++)) fi # Test 3: HTTPS-Verbindung (robust mit mehreren Methoden) progress "Teste HTTPS-Verbindung (robust)..." local max_attempts=20 local attempt=1 local connection_successful=false while [ $attempt -le $max_attempts ]; do # Methode 1: curl mit verschiedenen Optionen if curl -k -s --connect-timeout 3 --max-time 8 "$HTTPS_URL" >/dev/null 2>&1; then connection_successful=true break fi # Methode 2: wget als Fallback if command -v wget >/dev/null 2>&1; then if wget -q --no-check-certificate --timeout=3 --tries=1 "$HTTPS_URL" -O /dev/null 2>/dev/null; then connection_successful=true break fi fi # Methode 3: openssl s_client als direkter Test if echo "GET / HTTP/1.0" | openssl s_client -connect localhost:443 -quiet 2>/dev/null | grep -q "HTTP"; then connection_successful=true break fi progress "Warte auf HTTPS-Backend... ($attempt/$max_attempts)" sleep 3 ((attempt++)) done if [ "$connection_successful" = true ]; then success "✅ HTTPS-Backend erreichbar unter $HTTPS_URL" # Erweiterte Verbindungstests progress "Führe erweiterte HTTPS-Tests durch..." # Test Antwortzeit local response_time=$(curl -k -s -w "%{time_total}" -o /dev/null "$HTTPS_URL" 2>/dev/null || echo "timeout") if [ "$response_time" != "timeout" ]; then info "🕐 HTTPS Antwortzeit: ${response_time}s" # Bewerte Antwortzeit if [ "$(echo "$response_time < 2.0" | bc 2>/dev/null || echo "0")" -eq 1 ]; then success "✅ Gute Antwortzeit" elif [ "$(echo "$response_time < 5.0" | bc 2>/dev/null || echo "0")" -eq 1 ]; then info "ℹ️ Akzeptable Antwortzeit" else warning "⚠️ Langsame Antwortzeit" ((test_warnings++)) fi fi # Test HTTP-Status local http_status=$(curl -k -s -o /dev/null -w "%{http_code}" "$HTTPS_URL" 2>/dev/null || echo "000") if [ "$http_status" = "200" ]; then success "✅ HTTP Status 200 OK" else info "ℹ️ HTTP Status: $http_status (möglicherweise Redirect oder Login-Seite)" fi else error "❌ HTTPS-Backend nicht erreichbar nach $max_attempts Versuchen" ((test_errors++)) # Debugging-Informationen info "HTTPS-Debug Informationen:" netstat -tlnp | grep ":443" || info "Port 443 nicht gefunden" ss -tlnp | grep ":443" || info "Port 443 nicht in ss gefunden" fi # Test 4: SSL-Zertifikat (erweitert) progress "Teste SSL-Zertifikat (erweitert)..." # Methode 1: openssl s_client if echo | openssl s_client -connect localhost:443 -servername localhost 2>/dev/null | openssl x509 -noout -text >/dev/null 2>&1; then success "✅ SSL-Zertifikat ist gültig" # Zertifikat-Details extrahieren local cert_info=$(echo | openssl s_client -connect localhost:443 -servername localhost 2>/dev/null | openssl x509 -noout -subject -dates 2>/dev/null || echo "Nicht verfügbar") info "📜 Zertifikat-Info: $cert_info" else warning "⚠️ SSL-Zertifikat-Test fehlgeschlagen" ((test_warnings++)) # Alternative: Teste ob Zertifikat-Dateien existieren if [ -f "$APP_DIR/certs/localhost/localhost.crt" ] && [ -f "$APP_DIR/certs/localhost/localhost.key" ]; then info "📁 SSL-Zertifikat-Dateien sind vorhanden" # Teste Zertifikat-Datei direkt if openssl x509 -in "$APP_DIR/certs/localhost/localhost.crt" -noout -text >/dev/null 2>&1; then success "✅ SSL-Zertifikat-Datei ist gültig" else warning "⚠️ SSL-Zertifikat-Datei ist ungültig" ((test_warnings++)) fi fi fi # Test 5: Python-Anwendung Import-Test progress "Teste Python-Anwendung Import..." cd "$APP_DIR" 2>/dev/null || true # Setze Test-Umgebung export FLASK_ENV=testing export MYP_TESTING=1 export PYTHONPATH="$APP_DIR:${PYTHONPATH:-}" if timeout 15 python3 -c " import sys import os sys.path.insert(0, '$APP_DIR') os.chdir('$APP_DIR') try: import app print('✅ Flask-App Import erfolgreich') # Test ob Flask-App-Objekt verfügbar if hasattr(app, 'app'): print('✅ Flask-App-Objekt verfügbar') else: print('⚠️ Flask-App-Objekt nicht gefunden') except Exception as e: print(f'⚠️ App-Import-Problem: {e}') exit(1) " 2>&1; then success "✅ Python-Anwendung kann erfolgreich importiert werden" else warning "⚠️ Python-Anwendung Import-Probleme (möglicherweise nicht kritisch)" ((test_warnings++)) fi cd "$CURRENT_DIR" 2>/dev/null || true # Test 6: Verzeichnisstruktur-Validierung progress "Validiere Verzeichnisstruktur..." local structure_ok=true local required_files=("$APP_DIR/app.py" "$APP_DIR/models.py" "$APP_DIR/requirements.txt") local required_dirs=("$APP_DIR/static" "$APP_DIR/templates" "$APP_DIR/blueprints") for file in "${required_files[@]}"; do if [ ! -f "$file" ]; then warning "❌ Wichtige Datei fehlt: $file" structure_ok=false ((test_warnings++)) fi done for dir in "${required_dirs[@]}"; do if [ ! -d "$dir" ]; then warning "❌ Wichtiges Verzeichnis fehlt: $dir" structure_ok=false ((test_warnings++)) fi done if [ "$structure_ok" = true ]; then success "✅ Verzeichnisstruktur vollständig" fi # Zusammenfassung der Tests log "📊 System-Test Zusammenfassung:" log " ❌ Fehler: $test_errors" log " ⚠️ Warnungen: $test_warnings" if [ $test_errors -eq 0 ] && [ $test_warnings -eq 0 ]; then success "✅ Alle System-Tests erfolgreich - System vollständig funktionsfähig" return 0 elif [ $test_errors -eq 0 ]; then warning "⚠️ System-Tests mit $test_warnings Warnungen abgeschlossen - System grundsätzlich funktionsfähig" return 0 else error "❌ System-Tests mit $test_errors Fehlern fehlgeschlagen - System möglicherweise nicht funktionsfähig" return 1 fi } # =========================== AUFRÄUMEN =========================== cleanup_old_files() { log "=== AUFRÄUMEN ALTE DATEIEN ===" progress "Entferne alte Shell-Skripte..." # Entferne alte Skripte (falls vorhanden) local old_scripts=("combined.sh" "installer.sh") for script in "${old_scripts[@]}"; do if [ -f "$CURRENT_DIR/$script" ]; then progress "Entferne: $script" rm -f "$CURRENT_DIR/$script" || warning "Fehler beim Entfernen von $script" fi done log "✅ Aufräumen abgeschlossen" } # =========================== HAUPTMENÜ =========================== show_menu() { clear echo -e "${CYAN}=================================================================${NC}" echo -e "${CYAN} $APP_NAME - Setup-Skript v$APP_VERSION${NC}" echo -e "${CYAN}=================================================================${NC}" echo "" echo -e "${YELLOW}Bitte wählen Sie eine Option:${NC}" echo "" echo -e "${GREEN}1)${NC} Abhängigkeiten installieren und System für manuelles Testen vorbereiten" echo -e " ${BLUE}→ Python, Node.js, SSL-Zertifikate, Anwendung deployed, minimaler Test${NC}" echo -e " ${BLUE}→ System bereit für manuelle Tests und Entwicklung${NC}" echo "" echo -e "${GREEN}2)${NC} Vollständige Kiosk-Installation mit Remote-Zugang" echo -e " ${BLUE}→ Komplette Produktionsinstallation mit automatischem Kiosk-Start${NC}" echo -e " ${BLUE}→ RDP (root:744563017196A), SSH (user:raspberry), Firewall${NC}" echo -e " ${BLUE}→ Automatischer Login und Kiosk-Modus beim Boot${NC}" echo "" echo -e "${GREEN}3)${NC} Beenden" echo "" echo -e "${CYAN}=================================================================${NC}" echo -n "Ihre Wahl [1-3]: " } # =========================== INSTALLATIONS-MODI =========================== install_dependencies_only() { # Logging initialisieren init_logging log "=== MODUS: ROBUSTE ABHÄNGIGKEITEN-INSTALLATION FÜR MANUELLES TESTEN ===" # Grundlegende System-Validierung check_root check_system_resources check_debian_system check_internet_connection # System-Konfiguration configure_hostname update_system configure_network_security # Core-Abhängigkeiten installieren install_python_dependencies install_nodejs_npm install_ssl_certificates install_python_packages # Anwendung deployen deploy_application install_npm_dependencies generate_ssl_certificate # Services für manuelles Testen vorbereiten install_systemd_services enable_and_start_services # Performance-Optimierungen auch für manuelles Testen optimize_webapp_performance optimize_static_assets # Umfassende System-Tests progress "Starte umfassende System-Tests..." if test_application; then success "✅ Alle System-Tests erfolgreich!" else warning "⚠️ System-Tests mit Problemen - System möglicherweise eingeschränkt funktionsfähig" fi # Cleanup cleanup_old_files success "✅ Robuste Abhängigkeiten-Installation abgeschlossen!" log "📋 Installation Zusammenfassung:" log " 🖥️ Hostname: raspberrypi" log " 🐍 Python-Umgebung: Vollständig konfiguriert" log " 🌐 Node.js: Installiert und optimiert" log " 🔒 SSL-Zertifikate: Generiert und konfiguriert" log " 📁 Anwendung: In $APP_DIR deployed" log " ⚡ Performance: Optimiert für Raspberry Pi" log " 🔧 Services: Installiert und gestartet" info "" info "🚀 System bereit für manuelle Tests und Entwicklung!" info "🌐 HTTPS-Backend sollte verfügbar sein: $HTTPS_URL" info "⚙️ Manuelle App-Start Alternative: cd /opt/myp && python3 app.py" # Fehler-Zusammenfassung anzeigen show_error_summary } install_full_production_system() { # Logging initialisieren init_logging log "=== MODUS: VOLLSTÄNDIGE ROBUSTE KIOSK-INSTALLATION MIT REMOTE-ZUGANG ===" # Umfassende System-Validierung check_root check_system_resources check_debian_system check_internet_connection # System-Grundkonfiguration configure_hostname # Intelligente Abhängigkeiten-Installation if [ ! -d "$APP_DIR" ] || [ ! -f "$APP_DIR/app.py" ]; then warning "Anwendung noch nicht deployed - führe robuste Abhängigkeiten-Installation durch..." # Vollständige Basis-Installation update_system configure_network_security install_python_dependencies install_nodejs_npm install_ssl_certificates install_python_packages deploy_application install_npm_dependencies generate_ssl_certificate else info "Anwendung bereits deployed - überspringe Basis-Installation" # Trotzdem Netzwerk-Sicherheit aktualisieren configure_network_security fi # Desktop-Environments entfernen und minimale X11 installieren remove_desktop_environments install_minimal_x11 # Performance-Optimierungen für Raspberry Pi Webapp optimize_webapp_performance optimize_static_assets # Remote-Zugang konfigurieren (robust) install_remote_access configure_firewall # Kiosk-System konfigurieren create_kiosk_user configure_autologin configure_kiosk_autostart # Services installieren und aktivieren (robust) install_systemd_services enable_and_start_services # Umfassende System-Tests progress "Führe umfassende Produktions-System-Tests durch..." local system_tests_passed=true if test_application; then success "✅ Anwendungs-Tests erfolgreich" else warning "⚠️ Anwendungs-Tests mit Problemen" system_tests_passed=false fi if test_remote_access; then success "✅ Remote-Zugang-Tests erfolgreich" else warning "⚠️ Remote-Zugang-Tests mit Problemen" system_tests_passed=false fi # Aufräumen cleanup_old_files # Finale Status-Bewertung if [ "$system_tests_passed" = true ]; then success "✅ Vollständige robuste Kiosk-Installation erfolgreich abgeschlossen!" else warning "⚠️ Vollständige Kiosk-Installation mit Einschränkungen abgeschlossen" info "→ Grundfunktionalität sollte verfügbar sein, manuelle Überprüfung empfohlen" fi log "📋 Vollständige Installation Zusammenfassung:" log " 🖥️ Hostname: raspberrypi" log " 🔐 Kiosk-Modus: Konfiguriert (startet beim nächsten Boot)" log " 📡 SSH-Zugang: user:raspberry (Port 22)" log " 🖥️ RDP-Zugang: root:744563017196A (Port 3389)" log " 🔒 Firewall: Konfiguriert und aktiv" log " ⚡ Performance: Optimiert für Raspberry Pi" log " 🌐 HTTPS-Backend: $HTTPS_URL" log " 🛡️ Sicherheit: IPv6 deaktiviert, erweiterte Netzwerk-Sicherheit" info "" success "🚀 Produktionssystem vollständig einsatzbereit!" warning "⚠️ NEUSTART ERFORDERLICH für automatischen Kiosk-Start: sudo reboot" # Fehler-Zusammenfassung anzeigen show_error_summary } # =========================== RDP & SSH ZUGANG =========================== install_remote_access() { log "=== INSTALLIERE REMOTE-ZUGANG (RDP & SSH) ===" # SSH-Server installieren und konfigurieren progress "Installiere und konfiguriere SSH-Server..." apt-get install -y openssh-server || error "SSH-Server Installation fehlgeschlagen" # SSH-Service aktivieren systemctl enable ssh systemctl start ssh # SSH-Benutzer 'user' erstellen (falls nicht vorhanden) if ! id "user" &>/dev/null; then progress "Erstelle SSH-Benutzer: user" useradd -m -s /bin/bash user || error "Kann SSH-Benutzer nicht erstellen" echo "user:raspberry" | chpasswd || error "Kann Passwort für SSH-Benutzer nicht setzen" usermod -aG sudo user 2>/dev/null || true # pip-Konfiguration für SSH-Benutzer mkdir -p "/home/user/.pip" 2>/dev/null || true cat > "/home/user/.pip/pip.conf" << 'EOF' [global] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org timeout = 60 retries = 3 [install] break-system-packages = true trusted-host = pypi.org pypi.python.org files.pythonhosted.org EOF chown "user:user" "/home/user/.pip/pip.conf" 2>/dev/null || true log "✅ SSH-Benutzer 'user' erstellt mit Passwort 'raspberry'" else info "SSH-Benutzer 'user' existiert bereits" echo "user:raspberry" | chpasswd || warning "Konnte Passwort für SSH-Benutzer nicht aktualisieren" fi # RDP-Server (xrdp) installieren - vereinfachter Ansatz progress "Installiere RDP-Server (xrdp) - vereinfachte Installation..." # Alle bestehenden xrdp-Installationen entfernen progress "Entferne vorherige xrdp-Installationen..." systemctl stop xrdp xrdp-sesman 2>/dev/null || true systemctl disable xrdp xrdp-sesman 2>/dev/null || true apt-get remove --purge -y xrdp 2>/dev/null || true rm -rf /etc/xrdp /var/log/xrdp* 2>/dev/null || true # XFCE Desktop installieren (minimal) progress "Installiere minimale XFCE-Umgebung..." if ! apt-get install -y xfce4-session xfce4-panel xfce4-terminal xfce4-settings xfdesktop4 dbus-x11; then warning "Minimale XFCE-Installation fehlgeschlagen - verwende Fallback..." apt-get install -y xfce4 dbus-x11 || error "XFCE Installation fehlgeschlagen" fi # xrdp neu installieren progress "Installiere xrdp neu..." apt-get update apt-get install -y xrdp || error "xrdp Installation fehlgeschlagen" # Benutzer zur xrdp-Gruppe hinzufügen usermod -aG xrdp root 2>/dev/null || true if id "user" &>/dev/null; then usermod -aG xrdp user 2>/dev/null || true fi # Erstelle minimale xrdp-Konfiguration progress "Erstelle minimale xrdp-Konfiguration..." # Backup der Original-Konfiguration cp /etc/xrdp/xrdp.ini /etc/xrdp/xrdp.ini.original 2>/dev/null || true # Sehr einfache xrdp.ini cat > /etc/xrdp/xrdp.ini << 'EOF' [Globals] ini_version=1 fork=true port=3389 tcp_nodelay=true tcp_keepalive=true security_layer=rdp autorun= allow_channels=true allow_multimon=false bitmap_cache=true bitmap_compression=true bulk_compression=false max_bpp=24 new_cursors=true use_fastpath=both require_credentials=true ask_for_reconnect_reason=false enable_token_login=false [Xorg] name=Xorg lib=libxup.so username=ask password=ask ip=127.0.0.1 port=-1 code=20 EOF # Einfache sesman.ini cp /etc/xrdp/sesman.ini /etc/xrdp/sesman.ini.original 2>/dev/null || true cat > /etc/xrdp/sesman.ini << 'EOF' [Globals] ListenAddress=127.0.0.1 ListenPort=3350 EnableUserWindowManager=true UserWindowManager=startxfce4 DefaultWindowManager=startxfce4 [Security] AllowRootLogin=true MaxLoginRetry=4 AlwaysGroupCheck=false [Sessions] X11DisplayOffset=10 MaxSessions=10 KillDisconnected=false IdleTimeLimit=0 DisconnectedTimeLimit=0 [Logging] LogFile=xrdp-sesman.log LogLevel=INFO EnableSyslog=true SyslogLevel=INFO [Xorg] param1=-bs param2=-nolisten param3=tcp param4=-dpi param5=96 EOF # Erstelle .xsession für XFCE progress "Konfiguriere XFCE-Sessions..." # Root .xsession cat > /root/.xsession << 'EOF' #!/bin/bash export XDG_SESSION_DESKTOP=xfce export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg exec startxfce4 EOF chmod +x /root/.xsession # User .xsession (falls user existiert) if id "user" &>/dev/null; then cat > /home/user/.xsession << 'EOF' #!/bin/bash export XDG_SESSION_DESKTOP=xfce export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg exec startxfce4 EOF chown user:user /home/user/.xsession chmod +x /home/user/.xsession fi # Root-Passwort setzen progress "Setze Root-Passwort für RDP..." echo "root:744563017196A" | chpasswd || error "Kann Root-Passwort nicht setzen" # Log-Verzeichnisse erstellen mit korrekten Berechtigungen progress "Erstelle Log-Verzeichnisse..." mkdir -p /var/log touch /var/log/xrdp.log /var/log/xrdp-sesman.log 2>/dev/null || true chown xrdp:xrdp /var/log/xrdp*.log 2>/dev/null || true chmod 644 /var/log/xrdp*.log 2>/dev/null || true # Erstelle xrdp-Konfigurationsverzeichnisse mkdir -p /etc/xrdp/cert /var/run/xrdp chown xrdp:xrdp /etc/xrdp/cert /var/run/xrdp 2>/dev/null || true # Services aktivieren und starten progress "Starte xrdp-Services..." # systemd daemon reload systemctl daemon-reload # Services aktivieren systemctl enable xrdp-sesman systemctl enable xrdp # Services starten (sesman zuerst) systemctl start xrdp-sesman sleep 3 # Prüfe sesman-Status if systemctl is-active --quiet xrdp-sesman; then success "✅ xrdp-sesman erfolgreich gestartet" # Jetzt xrdp starten systemctl start xrdp sleep 3 if systemctl is-active --quiet xrdp; then success "✅ xrdp erfolgreich gestartet" else warning "⚠️ xrdp konnte nicht gestartet werden" journalctl -u xrdp --no-pager -l | tail -10 fi else warning "⚠️ xrdp-sesman konnte nicht gestartet werden" journalctl -u xrdp-sesman --no-pager -l | tail -10 fi cd "$CURRENT_DIR" # Finaler Status-Check if systemctl is-active --quiet xrdp && systemctl is-active --quiet xrdp-sesman; then log "✅ Remote-Zugang vollständig konfiguriert:" log " 📡 SSH: user:raspberry (Port 22)" log " 🖥️ RDP: root:744563017196A (Port 3389)" log " 🖥️ RDP: user:raspberry (Port 3389)" elif systemctl is-active --quiet ssh; then log "✅ SSH-Zugang konfiguriert:" log " 📡 SSH: user:raspberry (Port 22)" warning "⚠️ RDP-Installation unvollständig" info "Manuelle Überprüfung erforderlich:" info " systemctl status xrdp" info " systemctl status xrdp-sesman" info " journalctl -u xrdp -f" else error "❌ Weder SSH noch RDP konnten konfiguriert werden" fi } # =========================== FIREWALL KONFIGURATION =========================== configure_firewall() { log "=== KONFIGURIERE FIREWALL (firewalld) ===" # firewalld installieren progress "Installiere firewalld..." apt-get install -y firewalld || error "firewalld Installation fehlgeschlagen" # firewalld aktivieren und starten systemctl enable firewalld systemctl start firewalld # Warte kurz bis firewalld vollständig gestartet ist sleep 5 progress "Konfiguriere firewalld-Zonen und -Regeln..." # Firewall-Status prüfen if ! firewall-cmd --state >/dev/null 2>&1; then error "firewalld ist nicht aktiv oder reagiert nicht" fi # Bestehende Zone entfernen falls vorhanden progress "Entferne bestehende myp-backend Zone falls vorhanden..." if firewall-cmd --permanent --get-zones | grep -q "myp-backend"; then log "Entferne bestehende myp-backend Zone..." firewall-cmd --permanent --delete-zone=myp-backend 2>/dev/null || true firewall-cmd --reload sleep 2 fi # Zone neu erstellen progress "Erstelle neue myp-backend Zone..." if ! firewall-cmd --permanent --new-zone=myp-backend; then error "Fehler beim Erstellen der myp-backend Zone" fi # Konfiguration neu laden firewall-cmd --reload sleep 2 # Erweiterte Netzwerk-Quellen definieren (nur IPv4) progress "Füge Netzwerk-Quellen hinzu..." firewall-cmd --permanent --zone=myp-backend --add-source=192.168.0.0/16 || error "Fehler beim Hinzufügen des 192.168.0.0/16 Netzwerks" firewall-cmd --permanent --zone=myp-backend --add-source=127.0.0.1/32 || error "Fehler beim Hinzufügen von localhost" # Lokaler Hostname "raspberrypi" hinzufügen local local_hostname="raspberrypi" progress "Füge lokalen Hostname hinzu: $local_hostname" local local_ip=$(getent hosts "$local_hostname" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true) if [ -n "$local_ip" ]; then firewall-cmd --permanent --zone=myp-backend --add-source="$local_ip/32" 2>/dev/null || warning "Konnte lokalen Hostname nicht hinzufügen" log "✅ Lokaler Hostname $local_hostname hinzugefügt: $local_ip" else info "Lokaler Hostname $local_hostname nicht auflösbar - wird beim nächsten Boot verfügbar sein" fi # Frontend-Server m040tbaraspi001 hinzufügen (falls auflösbar) progress "Füge Frontend-Server hinzu: m040tbaraspi001" local frontend_ip=$(getent hosts "m040tbaraspi001" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true) if [ -n "$frontend_ip" ]; then firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_ip/32" 2>/dev/null || warning "Konnte Frontend-Server IP nicht hinzufügen" log "✅ Frontend-Server m040tbaraspi001 hinzugefügt: $frontend_ip" else # Versuche auch mit FQDN local frontend_fqdn_ip=$(getent hosts "m040tbaraspi001.de040.corpintra.net" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true) if [ -n "$frontend_fqdn_ip" ]; then firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_fqdn_ip/32" 2>/dev/null || warning "Konnte Frontend-Server FQDN nicht hinzufügen" log "✅ Frontend-Server m040tbaraspi001.de040.corpintra.net hinzugefügt: $frontend_fqdn_ip" else info "Frontend-Server m040tbaraspi001 nicht auflösbar - überspringe" fi fi # Ports und Services hinzufügen progress "Konfiguriere Ports und Services..." # HTTPS für API & Kiosk zulassen firewall-cmd --permanent --zone=myp-backend --add-port=443/tcp || error "Fehler beim Hinzufügen von Port 443" # SSH für Wartung firewall-cmd --permanent --zone=myp-backend --add-service=ssh || error "Fehler beim Hinzufügen des SSH-Service" # RDP für Remote-Desktop firewall-cmd --permanent --zone=myp-backend --add-port=3389/tcp || error "Fehler beim Hinzufügen von Port 3389" # IPv6 in firewalld deaktivieren progress "Deaktiviere IPv6 in firewalld..." firewall-cmd --permanent --set-target=DROP --zone=public --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in public Zone deaktiviert werden" firewall-cmd --permanent --set-target=DROP --zone=myp-backend --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in myp-backend Zone deaktiviert werden" # Default-Zone setzen progress "Setze Default-Zone..." firewall-cmd --set-default-zone=myp-backend || error "Fehler beim Setzen der Default-Zone" # Änderungen übernehmen progress "Lade Firewall-Konfiguration neu..." firewall-cmd --reload || error "Fehler beim Neuladen der Firewall-Konfiguration" # Kurz warten und Status prüfen sleep 3 # Firewall-Status anzeigen progress "Firewall-Konfiguration:" if firewall-cmd --list-all --zone=myp-backend 2>/dev/null; then log "✅ Firewall-Konfiguration erfolgreich angezeigt" else warning "⚠️ Firewall-Status konnte nicht angezeigt werden" fi # Finale Validierung progress "Validiere Firewall-Konfiguration..." local validation_errors=0 # Prüfe ob Zone existiert if ! firewall-cmd --get-zones | grep -q "myp-backend"; then error "Zone myp-backend wurde nicht korrekt erstellt" ((validation_errors++)) fi # Prüfe Default-Zone if [ "$(firewall-cmd --get-default-zone)" != "myp-backend" ]; then warning "Default-Zone ist nicht myp-backend" ((validation_errors++)) fi # Prüfe Ports if ! firewall-cmd --zone=myp-backend --query-port=443/tcp 2>/dev/null; then warning "Port 443 nicht korrekt konfiguriert" ((validation_errors++)) fi if ! firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then warning "Port 3389 nicht korrekt konfiguriert" ((validation_errors++)) fi if ! firewall-cmd --zone=myp-backend --query-service=ssh 2>/dev/null; then warning "SSH-Service nicht korrekt konfiguriert" ((validation_errors++)) fi if [ $validation_errors -eq 0 ]; then log "✅ Firewall konfiguriert und validiert:" log " 🔒 Zone: myp-backend (als Default gesetzt)" log " 🌐 Netzwerk: 192.168.0.0/16 (nur IPv4)" log " 🏠 Localhost: 127.0.0.1" log " 🖥️ Lokaler Host: raspberrypi" log " 📡 Frontend-Server: m040tbaraspi001" log " 🔌 Ports: 443/tcp (HTTPS), 22/tcp (SSH), 3389/tcp (RDP)" log " 🚫 IPv6 vollständig blockiert" else warning "⚠️ Firewall-Konfiguration mit $validation_errors Fehlern abgeschlossen" info "System funktioniert möglicherweise trotzdem - manuelle Überprüfung empfohlen" fi } # =========================== REMOTE-ZUGANG TESTEN =========================== test_remote_access() { log "=== TESTE REMOTE-ZUGANG ===" # SSH-Service testen progress "Teste SSH-Service..." if systemctl is-active --quiet ssh; then success "✅ SSH-Service läuft" # SSH-Port testen if ss -tlnp | grep -q ":22 "; then success "✅ SSH-Port 22 ist offen" else warning "⚠️ SSH-Port 22 nicht erreichbar" fi else warning "⚠️ SSH-Service läuft nicht" fi # RDP-Services testen progress "Teste RDP-Services..." local xrdp_sesman_status="❌" local xrdp_status="❌" if systemctl is-active --quiet xrdp-sesman; then xrdp_sesman_status="✅" success "✅ xrdp-sesman läuft" else warning "⚠️ xrdp-sesman läuft nicht" fi if systemctl is-active --quiet xrdp; then xrdp_status="✅" success "✅ xrdp läuft" # RDP-Port testen if ss -tlnp | grep -q ":3389 "; then success "✅ RDP-Port 3389 ist offen" else warning "⚠️ RDP-Port 3389 nicht erreichbar" fi else warning "⚠️ xrdp läuft nicht" fi # Firewall-Status testen progress "Teste Firewall-Status..." if systemctl is-active --quiet firewalld; then success "✅ Firewall läuft" # Prüfe ob Ports offen sind if firewall-cmd --zone=myp-backend --query-port=22/tcp 2>/dev/null; then success "✅ SSH-Port in Firewall freigegeben" else warning "⚠️ SSH-Port nicht in Firewall freigegeben" fi if firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then success "✅ RDP-Port in Firewall freigegeben" else warning "⚠️ RDP-Port nicht in Firewall freigegeben" fi else warning "⚠️ Firewall läuft nicht" fi # Netzwerk-Interface testen progress "Teste Netzwerk-Konfiguration..." local ip_address=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7}' | head -1 || echo "Unbekannt") if [ "$ip_address" != "Unbekannt" ]; then success "✅ Netzwerk-Interface aktiv: $ip_address" info "Zugang-URLs:" info " SSH: ssh user@$ip_address" if [ "$xrdp_status" = "✅" ]; then info " RDP: $ip_address:3389 (root:744563017196A oder user:raspberry)" fi else warning "⚠️ Keine Netzwerk-IP ermittelt" fi # Status-Zusammenfassung log "📊 Service-Status:" log " SSH: $(systemctl is-active --quiet ssh && echo "✅ Aktiv" || echo "❌ Inaktiv")" log " xrdp-sesman: $xrdp_sesman_status $(systemctl is-active --quiet xrdp-sesman && echo "Aktiv" || echo "Inaktiv")" log " xrdp: $xrdp_status $(systemctl is-active --quiet xrdp && echo "Aktiv" || echo "Inaktiv")" log "✅ Remote-Zugang-Test abgeschlossen" } # =========================== HOSTNAME KONFIGURATION =========================== configure_hostname() { log "=== KONFIGURIERE HOSTNAME ===" local target_hostname="raspberrypi" local current_hostname=$(hostname) if [ "$current_hostname" != "$target_hostname" ]; then progress "Setze Hostname von '$current_hostname' auf '$target_hostname'..." # Hostname sofort setzen hostnamectl set-hostname "$target_hostname" || error "Fehler beim Setzen des Hostnames" # /etc/hostname aktualisieren echo "$target_hostname" > /etc/hostname # /etc/hosts aktualisieren cp /etc/hosts /etc/hosts.backup sed -i "s/127.0.1.1.*/127.0.1.1\t$target_hostname/" /etc/hosts # Falls kein 127.0.1.1 Eintrag existiert, hinzufügen if ! grep -q "127.0.1.1" /etc/hosts; then echo "127.0.1.1 $target_hostname" >> /etc/hosts fi log "✅ Hostname erfolgreich auf '$target_hostname' gesetzt" else log "✅ Hostname bereits korrekt: '$target_hostname'" fi # Hostname-Auflösung testen if getent hosts "$target_hostname" >/dev/null 2>&1; then local resolved_ip=$(getent hosts "$target_hostname" | awk '{print $1}' | head -1) log "✅ Hostname-Auflösung funktioniert: $target_hostname -> $resolved_ip" else warning "⚠️ Hostname-Auflösung für '$target_hostname' fehlgeschlagen" fi } # =========================== WEBAPP PERFORMANCE-OPTIMIERUNG =========================== optimize_webapp_performance() { log "=== WEBAPP PERFORMANCE-OPTIMIERUNG FÜR RASPBERRY PI ===" # Python/Flask spezifische Optimierungen progress "Konfiguriere Python-Performance-Optimierungen..." # Python Bytecode Optimierung aktivieren cat > /etc/environment << 'EOF' # Python Performance Optimierungen PYTHONOPTIMIZE=2 PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PYTHONHASHSEED=random # Flask/SQLite Optimierungen FLASK_ENV=production FLASK_DEBUG=0 SQLITE_TMPDIR=/tmp # Memory Optimierungen MALLOC_ARENA_MAX=2 MALLOC_MMAP_THRESHOLD=131072 MALLOC_TRIM_THRESHOLD=131072 EOF # Systemd Service-Optimierungen progress "Optimiere Systemd-Services für bessere Performance..." # Stoppe unnötige Services local unnecessary_services=( "bluetooth.service" "hciuart.service" "avahi-daemon.service" "cups.service" "cups-browsed.service" "ModemManager.service" "wpa_supplicant.service" ) for service in "${unnecessary_services[@]}"; do if systemctl is-enabled "$service" 2>/dev/null; then systemctl disable "$service" 2>/dev/null || true systemctl stop "$service" 2>/dev/null || true log "✅ Service deaktiviert: $service" fi done # Tmpfs für temporäre Dateien progress "Konfiguriere tmpfs für bessere I/O Performance..." cat >> /etc/fstab << 'EOF' # MYP Performance Optimierungen - tmpfs für temporäre Dateien tmpfs /tmp tmpfs defaults,noatime,nosuid,size=256m 0 0 tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=128m 0 0 tmpfs /var/log tmpfs defaults,noatime,nosuid,size=64m 0 0 EOF # Logrotate für tmpfs-Logs konfigurieren cat > /etc/logrotate.d/myp-tmpfs << 'EOF' /var/log/*.log { daily missingok rotate 2 compress notifempty create 0644 root root copytruncate } EOF # Systemd Journal Einstellungen optimieren progress "Optimiere systemd Journal für bessere Performance..." mkdir -p /etc/systemd/journald.conf.d cat > /etc/systemd/journald.conf.d/myp-performance.conf << 'EOF' [Journal] # Journal Optimierungen für Raspberry Pi Storage=volatile RuntimeMaxUse=32M RuntimeKeepFree=16M RuntimeMaxFileSize=8M RuntimeMaxFiles=4 MaxRetentionSec=1day MaxFileSec=1hour ForwardToSyslog=no ForwardToKMsg=no ForwardToConsole=no ForwardToWall=no EOF # Crontab für regelmäßige Cache-Bereinigung progress "Installiere automatische Cache-Bereinigung..." cat > /etc/cron.d/myp-cache-cleanup << 'EOF' # MYP Cache und Memory Cleanup # Alle 6 Stunden Cache bereinigen 0 */6 * * * root /bin/echo 3 > /proc/sys/vm/drop_caches # Täglich um 3 Uhr temporäre Dateien bereinigen 0 3 * * * root /usr/bin/find /tmp -type f -atime +1 -delete 2>/dev/null # Wöchentlich Python Cache bereinigen 0 2 * * 0 root /usr/bin/find /opt/myp -name "*.pyc" -delete 2>/dev/null 0 2 * * 0 root /usr/bin/find /opt/myp -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null EOF # Limits für bessere Ressourcen-Verwaltung progress "Konfiguriere System-Limits..." cat >> /etc/security/limits.conf << 'EOF' # MYP Performance Limits * soft nofile 65536 * hard nofile 65536 * soft nproc 32768 * hard nproc 32768 root soft nofile 65536 root hard nofile 65536 EOF # Apache/Nginx entfernen falls vorhanden (Konflikt mit Flask) progress "Entferne konfliktbehaftete Webserver..." local webservers=("apache2" "nginx" "lighttpd") for webserver in "${webservers[@]}"; do if systemctl is-enabled "$webserver" 2>/dev/null; then systemctl stop "$webserver" 2>/dev/null || true systemctl disable "$webserver" 2>/dev/null || true apt-get remove --purge -y "$webserver" 2>/dev/null || true log "✅ Webserver entfernt: $webserver" fi done log "✅ Webapp Performance-Optimierung abgeschlossen:" log " 🚀 Python Bytecode-Optimierung aktiviert" log " 💾 tmpfs für temporäre Dateien konfiguriert" log " 📝 Journal-Logging optimiert" log " 🧹 Automatische Cache-Bereinigung installiert" log " ⚡ Unnötige Services deaktiviert" log " 📊 System-Limits für bessere Performance gesetzt" } # =========================== CSS/JS OPTIMIERUNG =========================== optimize_static_assets() { log "=== STATISCHE DATEIEN OPTIMIERUNG ===" if [ ! -d "$APP_DIR/static" ]; then warning "Static-Ordner nicht gefunden - überspringe Asset-Optimierung" return fi progress "Analysiere und optimiere CSS/JS Dateien..." cd "$APP_DIR/static" # Erstelle optimierte CSS-Datei durch Kombination kritischer Styles progress "Erstelle optimierte CSS-Kombination..." cat > css/critical.min.css << 'EOF' /* Kritische Styles für ersten Seitenaufbau - Inline-optimiert */ *{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif;line-height:1.5} .container{max-width:1200px;margin:0 auto;padding:0 1rem} .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} .btn{display:inline-flex;align-items:center;padding:0.5rem 1rem;border:none;border-radius:0.375rem;font-weight:500;text-decoration:none;cursor:pointer;transition:all 0.15s} .btn-primary{background:#3b82f6;color:white}.btn-primary:hover{background:#2563eb} .card{background:white;border-radius:0.5rem;padding:1.5rem;box-shadow:0 1px 3px rgba(0,0,0,0.1)} .flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between} .hidden{display:none}.block{display:block}.inline-block{display:inline-block} .text-sm{font-size:0.875rem}.text-lg{font-size:1.125rem} .font-medium{font-weight:500}.font-bold{font-weight:700} .text-gray-600{color:#4b5563}.text-gray-900{color:#111827} .mb-4{margin-bottom:1rem}.mt-6{margin-top:1.5rem}.p-4{padding:1rem} .w-full{width:100%}.h-full{height:100%} @media(max-width:768px){.container{padding:0 0.5rem}.card{padding:1rem}} EOF # Erstelle minimale JavaScript-Loader progress "Erstelle optimierten JavaScript-Loader..." cat > js/loader.min.js << 'EOF' /*Minimaler Async Loader für bessere Performance*/ (function(){var d=document,w=window;function loadCSS(href){var l=d.createElement('link');l.rel='stylesheet';l.href=href;l.media='print';l.onload=function(){this.media='all'};d.head.appendChild(l)}function loadJS(src,cb){var s=d.createElement('script');s.async=true;s.src=src;if(cb)s.onload=cb;d.head.appendChild(s)}w.loadAssets=function(){if(w.assetsLoaded)return;w.assetsLoaded=true;loadCSS('/static/css/tailwind.min.css');loadJS('/static/js/app.min.js')};if(d.readyState==='loading'){d.addEventListener('DOMContentLoaded',w.loadAssets)}else{w.loadAssets()}})(); EOF # Service Worker für besseres Caching progress "Erstelle optimierten Service Worker..." cat > sw-optimized.js << 'EOF' const CACHE_NAME = 'myp-webapp-v1'; const ASSETS_TO_CACHE = [ '/', '/static/css/critical.min.css', '/static/js/loader.min.js', '/static/favicon.svg' ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(ASSETS_TO_CACHE)) ); }); self.addEventListener('fetch', event => { if (event.request.destination === 'image' || event.request.url.includes('/static/')) { event.respondWith( caches.match(event.request) .then(response => response || fetch(event.request)) ); } }); EOF # Gzip-Kompression für statische Dateien progress "Komprimiere statische Dateien..." find . -name "*.css" -o -name "*.js" -o -name "*.html" | while read file; do if [ -f "$file" ] && [ ! -f "$file.gz" ]; then gzip -c "$file" > "$file.gz" 2>/dev/null || true fi done cd "$CURRENT_DIR" log "✅ Statische Dateien optimiert:" log " 📦 Kritische CSS-Styles kombiniert" log " ⚡ Asynchroner Asset-Loader erstellt" log " 🗜️ Gzip-Kompression angewendet" log " 🔄 Service Worker für Caching installiert" } # =========================== HAUPTPROGRAMM =========================== main() { # Erstelle logs-Verzeichnis im aktuellen Projektverzeichnis mkdir -p "logs" 2>/dev/null || true while true; do show_menu read -r choice case $choice in 1) install_dependencies_only echo "" echo -e "${BLUE}📁 Log-Dateien zur Überprüfung:${NC}" echo -e " 📄 Vollständiges Log: $INSTALL_LOG" [ $ERROR_COUNT -gt 0 ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG" [ $WARNING_COUNT -gt 0 ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG" echo -e " 🔍 Debug-Log: $DEBUG_LOG" echo -e " 📊 Zusammenfassung: logs/myp-install-summary.txt" echo "" echo -n "Drücken Sie Enter um fortzufahren..." read -r ;; 2) install_full_production_system echo "" echo -e "${BLUE}📁 Log-Dateien zur Überprüfung:${NC}" echo -e " 📄 Vollständiges Log: $INSTALL_LOG" [ $ERROR_COUNT -gt 0 ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG" [ $WARNING_COUNT -gt 0 ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG" echo -e " 🔍 Debug-Log: $DEBUG_LOG" echo -e " 📊 Zusammenfassung: logs/myp-install-summary.txt" echo "" echo -n "Drücken Sie Enter um fortzufahren..." read -r ;; 3) echo "" echo -e "${CYAN}Setup-Skript beendet${NC}" if [ -f "$INSTALL_LOG" ]; then echo -e "${BLUE}📁 Verfügbare Log-Dateien:${NC}" echo -e " 📄 Vollständiges Log: $INSTALL_LOG" [ -f "$ERROR_LOG" ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG" [ -f "$WARNING_LOG" ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG" [ -f "$DEBUG_LOG" ] && echo -e " 🔍 Debug-Log: $DEBUG_LOG" [ -f "logs/myp-install-summary.txt" ] && echo -e " 📊 Zusammenfassung: logs/myp-install-summary.txt" fi exit 0 ;; *) echo -e "${RED}Ungültige Auswahl. Bitte wählen Sie 1-3.${NC}" ;; esac done } # Skript starten main "$@"