#!/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 HTTP_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)" # Log-Dateien - verwende relatives logs-Verzeichnis mkdir -p "$CURRENT_DIR/logs" 2>/dev/null || true INSTALL_LOG="$CURRENT_DIR/logs/install.log" ERROR_LOG="$CURRENT_DIR/logs/errors.log" WARNING_LOG="$CURRENT_DIR/logs/warnings.log" DEBUG_LOG="$CURRENT_DIR/logs/debug.log" readonly HTTP_PORT="5000" readonly HTTP_URL="http://localhost:${HTTP_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() { # Sichere Log-Verzeichnis-Erstellung if ! mkdir -p "$CURRENT_DIR/logs" 2>/dev/null; then echo "FEHLER: Kann logs-Verzeichnis nicht erstellen - verwende /tmp" >&2 INSTALL_LOG="/tmp/myp-install.log" ERROR_LOG="/tmp/myp-install-errors.log" WARNING_LOG="/tmp/myp-install-warnings.log" DEBUG_LOG="/tmp/myp-install-debug.log" fi # Überschreibe bestehende Log-Dateien { echo "=================================================================" echo "MYP Installation Log - $(date '+%Y-%m-%d %H:%M:%S')" echo "Script Version: $APP_VERSION" echo "System: $(timeout 5 uname -a 2>/dev/null || echo 'System-Info nicht verfügbar')" echo "Arbeitsverzeichnis: $CURRENT_DIR" echo "Log-Verzeichnis: $(dirname "$INSTALL_LOG")" echo "=================================================================" echo "" } > "$INSTALL_LOG" 2>/dev/null || { echo "KRITISCH: Kann Haupt-Log nicht schreiben!" >&2 exit 1 } { 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="$CURRENT_DIR/logs/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 "=== ANTI-HÄNGE SYSTEM-UPDATE MIT TIMEOUTS ===" progress "Konfiguriere APT für bessere Zuverlässigkeit (timeout-gesichert)..." # APT-Konfiguration optimieren (aggressivere Timeouts) timeout 10 bash -c 'cat > /etc/apt/apt.conf.d/99myp-optimized << "EOF" APT::Acquire::Retries "2"; APT::Acquire::http::Timeout "15"; APT::Acquire::https::Timeout "15"; APT::Acquire::ftp::Timeout "15"; APT::Install-Recommends "false"; APT::Install-Suggests "false"; Dpkg::Options { "--force-confdef"; "--force-confold"; } APT::Get::Assume-Yes "true"; APT::Get::Fix-Broken "true"; EOF' || warning "APT-Konfiguration timeout - verwende Defaults" # Repository-Listen korrigieren (timeout-gesichert) progress "Validiere APT-Repositories (timeout-gesichert)..." timeout 20 bash -c ' if [ -f /etc/apt/sources.list ]; then cp /etc/apt/sources.list /etc/apt/sources.list.backup 2>/dev/null || true if grep -q "deb-src" /etc/apt/sources.list 2>/dev/null; then sed -i "s/^deb-src/#deb-src/g" /etc/apt/sources.list 2>/dev/null || true echo "Source-Repositories deaktiviert" fi fi ' || warning "Repository-Validierung timeout - fahre fort" # APT-Lock-Dateien bereinigen (falls hängend) progress "Bereinige APT-Lock-Dateien..." timeout 10 bash -c ' rm -f /var/lib/dpkg/lock-frontend 2>/dev/null || true rm -f /var/lib/dpkg/lock 2>/dev/null || true rm -f /var/cache/apt/archives/lock 2>/dev/null || true rm -f /var/lib/apt/lists/lock 2>/dev/null || true ' || true progress "Aktualisiere Paketlisten (max 60s timeout)..." if timeout 60 apt-get update 2>/dev/null; then success "✅ APT Update erfolgreich" else warning "⚠️ APT Update timeout - fahre ohne Update fort" fi progress "Führe System-Upgrade durch (max 120s timeout)..." if timeout 120 bash -c 'DEBIAN_FRONTEND=noninteractive apt-get upgrade -y 2>/dev/null'; then success "✅ System Upgrade erfolgreich" else warning "⚠️ System Upgrade timeout - fahre ohne Upgrade fort" fi 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 "=== PYTHON-PAKETE INSTALLATION ===" progress "Installiere Python-Pakete..." 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 # Installiere alle Pakete aus requirements.txt progress "Installiere requirements.txt..." if python3 -m pip install -r "$CURRENT_DIR/requirements.txt" --break-system-packages; then success "✅ requirements.txt erfolgreich installiert" else error "❌ requirements.txt Installation fehlgeschlagen" return 1 fi # Validiere essenzielle Module progress "Validiere essenzielle Python-Module..." local essential_modules=("flask" "requests") local validation_success=true for module in "${essential_modules[@]}"; do if 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" fi log "✅ Python-Pakete Installation abgeschlossen" # Zeige installierte Pakete progress "Zeige installierte Python-Pakete..." echo "" echo "📦 Installierte Python-Pakete:" python3 -m pip list 2>/dev/null | grep -E "(Flask|requests|Werkzeug|Jinja2)" | head -10 || echo " Keine relevanten Pakete gefunden" echo "" } # =========================== 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 "=== SIMPLE NETZWERK-SICHERHEIT (ANTI-HÄNGE VERSION) ===" # Standardmäßig überspringen um Hänger zu vermeiden if [ "${SKIP_NETWORK_SECURITY:-1}" = "1" ]; then info "🚀 Netzwerk-Sicherheit übersprungen für schnellere Installation" info "📝 Kann später manuell aktiviert werden mit: SKIP_NETWORK_SECURITY=0" return fi # Komplette Funktion mit aggressivem Timeout if ! timeout 30 bash -c ' # Nur essenzielle IPv6-Deaktivierung progress() { echo "[FORTSCHRITT] $1"; } warning() { echo "[WARNUNG] $1"; } success() { echo "[ERFOLG] $1"; } progress "Deaktiviere IPv6 (essentiell, max 30s)..." # 1. Einfache sysctl IPv6-Deaktivierung (schnell) echo "net.ipv6.conf.all.disable_ipv6=1" > /etc/sysctl.d/99-myp-ipv6.conf 2>/dev/null || true echo "net.ipv6.conf.default.disable_ipv6=1" >> /etc/sysctl.d/99-myp-ipv6.conf 2>/dev/null || true # 2. IPv6 in /etc/hosts auskommentieren (schnell) if [ -f /etc/hosts ]; then sed -i.backup "s/^::1/#::1/" /etc/hosts 2>/dev/null || true fi # 3. GRUB nur wenn schnell verfügbar if [ -f /etc/default/grub ] && command -v update-grub >/dev/null 2>&1; then if ! grep -q "ipv6.disable=1" /etc/default/grub 2>/dev/null; then cp /etc/default/grub /etc/default/grub.backup 2>/dev/null || true sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\"/&ipv6.disable=1 /" /etc/default/grub 2>/dev/null || true # update-grub nur mit 10s timeout if timeout 10 update-grub >/dev/null 2>&1; then success "GRUB IPv6 deaktiviert" else warning "GRUB-Update timeout - wird beim nächsten Boot aktiv" fi fi fi success "IPv6-Deaktivierung abgeschlossen" '; then warning "⚠️ Netzwerk-Sicherheit timeout (30s) - überspringe" info " → System funktioniert trotzdem normal" info " → IPv6-Deaktivierung kann später manuell durchgeführt werden" else log "✅ Basis-Netzwerk-Sicherheit konfiguriert:" log " 🚫 IPv6 deaktiviert" log " 📝 Konfiguration in /etc/sysctl.d/99-myp-ipv6.conf" log " 🔄 Wird beim nächsten Boot vollständig aktiv" fi } # =========================== 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" } # =========================== X11 KONFIGURATION FÜR RASPBERRY PI =========================== configure_x11_for_raspberry_pi() { log "=== KONFIGURIERE X11 FÜR RASPBERRY PI ===" progress "Erstelle X11-Konfiguration für Raspberry Pi..." # Erstelle xorg.conf.d Verzeichnis mkdir -p /etc/X11/xorg.conf.d # Erstelle 99-fbdev.conf um Framebuffer-Fehler zu beheben cat > /etc/X11/xorg.conf.d/99-fbdev.conf << 'XORGEOF' # X11 Konfiguration für Raspberry Pi - behebt Framebuffer-Fehler Section "Device" Identifier "Raspberry Pi FBDEV" Driver "fbdev" Option "fbdev" "/dev/fb0" Option "SwapbuffersWait" "true" EndSection Section "Screen" Identifier "Primary Screen" Device "Raspberry Pi FBDEV" DefaultDepth 24 SubSection "Display" Depth 24 Modes "1920x1080" "1680x1050" "1600x900" "1280x1024" "1280x800" "1024x768" EndSubSection EndSection Section "ServerLayout" Identifier "Default Layout" Screen "Primary Screen" EndSection Section "ServerFlags" Option "BlankTime" "0" Option "StandbyTime" "0" Option "SuspendTime" "0" Option "OffTime" "0" Option "DPMS" "false" EndSection XORGEOF # Alternative: Verwende modesetting Treiber statt fbdev cat > /etc/X11/xorg.conf.d/20-modesetting.conf << 'MODESETEOF' # Alternative Modesetting-Konfiguration Section "Device" Identifier "Raspberry Pi Modesetting" Driver "modesetting" Option "AccelMethod" "none" EndSection MODESETEOF # Erstelle Wrapper-Skript für X11-Start mit korrekten Parametern cat > /usr/local/bin/start-x11-kiosk << 'KIOSKSTARTEOF' #!/bin/bash # X11 Kiosk-Start-Wrapper für Raspberry Pi # Behebt Framebuffer und Permission-Probleme export DISPLAY=:0 export XAUTHORITY=/home/kiosk/.Xauthority # Erstelle .Xauthority falls nicht vorhanden if [ ! -f "$XAUTHORITY" ]; then touch "$XAUTHORITY" chown kiosk:kiosk "$XAUTHORITY" chmod 600 "$XAUTHORITY" fi # Stoppe eventuell laufende X-Server pkill -f "X :0" 2>/dev/null || true pkill -f "Xorg" 2>/dev/null || true sleep 2 # Versuche verschiedene X-Server Start-Methoden echo "Starte X-Server für Kiosk-Modus..." # Methode 1: Mit vt und novtswitch (empfohlen für Raspberry Pi) if ! xinit /home/kiosk/.xinitrc -- :0 vt7 -novtswitch -nolisten tcp -dpi 96 2>/tmp/x11-error.log; then echo "Methode 1 fehlgeschlagen, versuche Alternative..." # Methode 2: Mit config und ignoreABI if ! xinit /home/kiosk/.xinitrc -- :0 vt7 -config /etc/X11/xorg.conf.d/99-fbdev.conf -ignoreABI 2>>/tmp/x11-error.log; then echo "Methode 2 fehlgeschlagen, versuche Fallback..." # Methode 3: Minimaler Start xinit /home/kiosk/.xinitrc -- :0 2>>/tmp/x11-error.log fi fi # Fehlerlog anzeigen bei Problem if [ -f /tmp/x11-error.log ]; then echo "X11 Fehler-Log:" tail -20 /tmp/x11-error.log fi KIOSKSTARTEOF chmod +x /usr/local/bin/start-x11-kiosk # Installiere fehlende Video-Treiber progress "Installiere Video-Treiber für Raspberry Pi..." apt-get install -y xserver-xorg-video-fbturbo 2>/dev/null || { # Fallback zu Standard-Treibern apt-get install -y xserver-xorg-video-all 2>/dev/null || true } # Raspberry Pi spezifische Video-Treiber if [ -f /boot/config.txt ]; then progress "Konfiguriere Raspberry Pi GPU-Einstellungen..." # Backup config.txt cp /boot/config.txt /boot/config.txt.backup # GPU-Speicher erhöhen für bessere Grafik-Performance if ! grep -q "^gpu_mem=" /boot/config.txt; then echo "gpu_mem=128" >> /boot/config.txt fi # HDMI-Einstellungen für bessere Kompatibilität if ! grep -q "^hdmi_force_hotplug=" /boot/config.txt; then cat >> /boot/config.txt << 'BOOTEOF' # X11 Kiosk-Modus Optimierungen hdmi_force_hotplug=1 hdmi_drive=2 config_hdmi_boost=4 disable_overscan=1 framebuffer_width=1920 framebuffer_height=1080 framebuffer_depth=32 framebuffer_ignore_alpha=1 BOOTEOF fi fi # Erstelle alternatives .xinitrc für kiosk User cat > /home/kiosk/.xinitrc-fixed << 'XINITRCEOF' #!/bin/bash # Fehlerbehandlung set -e exec 2>/tmp/xinitrc-error.log # X11 Einstellungen xset s off xset s noblank xset -dpms # Mauszeiger verstecken unclutter -idle 0.1 -root -noevents & # Window Manager starten (lightweight) openbox-session & # Warte kurz sleep 2 # Browser 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 # Starte Browser im Kiosk-Modus exec $BROWSER \ --kiosk \ --no-sandbox \ --disable-gpu-sandbox \ --disable-software-rasterizer \ --disable-dev-shm-usage \ --disable-setuid-sandbox \ --disable-gpu \ --no-first-run \ --noerrdialogs \ --disable-infobars \ --start-fullscreen \ http://localhost:5000 XINITRCEOF chmod +x /home/kiosk/.xinitrc-fixed chown kiosk:kiosk /home/kiosk/.xinitrc-fixed # Aktualisiere die .bashrc für den alternativen Start cat > /home/kiosk/.bashrc-kiosk << 'BASHRCEOF4' # Kiosk-Autostart mit X11-Fixes if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then echo "Starte Kiosk-Modus mit X11-Fixes..." # Verwende das neue Start-Skript exec /usr/local/bin/start-x11-kiosk fi BASHRCEOF4 log "✅ X11-Konfiguration für Raspberry Pi erstellt" info " 📁 Konfiguration: /etc/X11/xorg.conf.d/" info " 🚀 Start-Skript: /usr/local/bin/start-x11-kiosk" info " 🔧 Alternative .xinitrc: /home/kiosk/.xinitrc-fixed" } # =========================== 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 HTTP-Backend echo "Warte auf HTTP-Backend..." for i in {1..60}; do if curl -s http://localhost:5000 >/dev/null 2>&1; then echo "HTTP-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 \ http://localhost:5000 else exec firefox-esr \ --kiosk \ http://localhost:5000 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" # X11-Autorisierung für kiosk-User konfigurieren progress "Konfiguriere X11-Autorisierung für kiosk-User..." # Erstelle .Xauthority Datei touch "$kiosk_home/.Xauthority" chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority" chmod 600 "$kiosk_home/.Xauthority" # Füge DISPLAY-Variable zum .bashrc hinzu if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then cat >> "$kiosk_home/.bashrc" << 'BASHRCEOF3' # X11 Display Konfiguration export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority # X11 Session Management if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then export DISPLAY=:0.0 fi BASHRCEOF3 chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" fi # Erstelle X11-Startup-Hilfsskript cat > "$kiosk_home/start-x11.sh" << 'EOF' #!/bin/bash # X11-Startup-Hilfsskript für kiosk-User # Behebt .Xauthority und DISPLAY-Probleme export HOME=/home/kiosk export USER=kiosk export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority # Erstelle .Xauthority falls nicht vorhanden if [ ! -f "$XAUTHORITY" ]; then touch "$XAUTHORITY" chmod 600 "$XAUTHORITY" fi # Prüfe ob X11-Server läuft if ! pgrep -x "X" > /dev/null && ! pgrep -x "Xorg" > /dev/null; then echo "Starte X11-Server..." startx /home/kiosk/.xinitrc -- :0 vt1 & sleep 3 fi # Warte bis X11-Server verfügbar ist timeout=30 elapsed=0 while [ $elapsed -lt $timeout ]; do if xset q >/dev/null 2>&1; then echo "X11-Server ist bereit" break fi sleep 1 elapsed=$((elapsed + 1)) done if [ $elapsed -ge $timeout ]; then echo "FEHLER: X11-Server nicht verfügbar nach ${timeout}s" exit 1 fi echo "X11-Session erfolgreich gestartet" EOF chmod +x "$kiosk_home/start-x11.sh" chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/start-x11.sh" log "✅ Automatischer Kiosk-Start konfiguriert" info "Der Kiosk-Modus startet automatisch beim Login des $KIOSK_USER" # Wenn X11-Konfiguration für Raspberry Pi vorhanden ist, verwende sie if [ -f /usr/local/bin/start-x11-kiosk ]; then progress "Aktualisiere .bashrc für X11-Fix-Integration..." # Backup der aktuellen .bashrc cp "$kiosk_home/.bashrc" "$kiosk_home/.bashrc.backup" # Verwende die korrigierte Version cat > "$kiosk_home/.bashrc" << 'BASHRCFIXED' # Automatischer Kiosk-Start beim Login mit X11-Fixes if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then echo "Starte Kiosk-Modus mit X11-Fixes..." # Verwende das X11-Fix Start-Skript wenn vorhanden if [ -x /usr/local/bin/start-x11-kiosk ]; then exec /usr/local/bin/start-x11-kiosk else # Fallback zum normalen Start startx /home/kiosk/.xinitrc -- :0 vt1 & sleep 5 export DISPLAY=:0 # Warte auf HTTP-Backend echo "Warte auf HTTP-Backend..." for i in {1..60}; do if curl -s http://localhost:5000 >/dev/null 2>&1; then echo "HTTP-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 \ http://localhost:5000 else exec firefox-esr \ --kiosk \ http://localhost:5000 fi fi fi BASHRCFIXED chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" log "✅ .bashrc für X11-Fix-Integration aktualisiert" fi } # =========================== ROBUSTE SSL-ZERTIFIKATE INSTALLATION =========================== install_ssl_certificates() { log "=== ANTI-HÄNGE SSL-ZERTIFIKATE KONFIGURATION ===" progress "Installiere SSL-Grundkomponenten (timeout-gesichert)..." if timeout 60 apt-get install -y ca-certificates openssl 2>/dev/null; then success "✅ SSL-Grundkomponenten installiert" else warning "⚠️ SSL-Installation timeout - verwende bestehende" fi progress "Überspringe CA-Update um Hänger zu vermeiden..." info "💡 CA-Zertifikate werden beim nächsten Boot automatisch aktualisiert" # SSL-Verzeichnisse sicherstellen (timeout-gesichert) timeout 10 mkdir -p /usr/local/share/ca-certificates/myp 2>/dev/null || true # Mercedes Corporate Zertifikate (ultra-vereinfacht) if [ -d "$CURRENT_DIR/certs/mercedes" ] && [ "$(ls -A $CURRENT_DIR/certs/mercedes 2>/dev/null)" ]; then progress "Kopiere Mercedes-Zertifikate (max 30s)..." # Sehr einfacher und schneller Ansatz timeout 30 bash -c ' cert_count=0 find "$1/certs/mercedes" -name "*.crt" -o -name "*.pem" | head -5 | while read cert_file; do cert_count=$((cert_count + 1)) cert_name="mercedes-$(basename "$cert_file" | cut -d. -f1)" if cp "$cert_file" "/usr/local/share/ca-certificates/myp/${cert_name}.crt" 2>/dev/null; then echo "Zertifikat kopiert: $cert_name" fi [ $cert_count -ge 5 ] && break done ' -- "$CURRENT_DIR" 2>/dev/null || warning "Mercedes-Zertifikate timeout - überspringe" info "Mercedes-Zertifikate werden beim nächsten Boot aktiv" else info "Keine Mercedes-Zertifikate gefunden" fi # SSL-Umgebungsvariablen setzen (timeout-gesichert) progress "Konfiguriere SSL-Umgebungsvariablen (schnell)..." timeout 10 bash -c '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' || warning "SSL-Umgebungsvariablen timeout" # SSL-Umgebungsvariablen für aktuelle Session export SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true export CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true log "✅ SSL-Zertifikate anti-hänge konfiguriert" info "📝 CA-Updates werden automatisch beim nächsten Boot durchgeführt" } # =========================== 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 Updates (optional - überspringen bei Problemen) progress "Versuche Bash-Profile zu aktualisieren (optional)..." # Führe Updates nur in einem Subshell mit Timeout aus ( # Setze eine maximale Laufzeit von 10 Sekunden für alle Bash-Profile Updates export BASH_PROFILE_TIMEOUT=10 # Starte einen Background-Timer (sleep $BASH_PROFILE_TIMEOUT && kill -TERM $$ 2>/dev/null) & local timer_pid=$! # Nur /root/.bashrc aktualisieren (schnell und sicher) if [ -f "/root/.bashrc" ] && [ -w "/root/.bashrc" ]; then if ! grep -q "MYP Application Environment" "/root/.bashrc" 2>/dev/null; then echo "" >> "/root/.bashrc" echo "# MYP Application Environment" >> "/root/.bashrc" echo 'if [ -d "/opt/myp" ]; then' >> "/root/.bashrc" echo ' export MYP_APP_DIR="/opt/myp"' >> "/root/.bashrc" echo ' export FLASK_APP="/opt/myp/app.py"' >> "/root/.bashrc" echo ' export FLASK_ENV="production"' >> "/root/.bashrc" echo ' export PYTHONPATH="/opt/myp:${PYTHONPATH:-}"' >> "/root/.bashrc" echo 'fi' >> "/root/.bashrc" log "✅ Root Bash-Profile aktualisiert" fi fi # Timer beenden kill $timer_pid 2>/dev/null || true ) 2>/dev/null || { warning "⚠️ Bash-Profile Update übersprungen (Timeout oder Fehler)" debug "Bash-Profile Updates sind optional - Installation wird fortgesetzt" } # 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 " 🔧 Bash-Profile konfiguriert" log " 🛡️ Sichere Berechtigungen gesetzt" } # =========================== BERECHTIGEN-MANAGEMENT =========================== fix_project_permissions() { log "=== BERECHTIGEN-MANAGEMENT FÜR KIOSK-USER ===" progress "Korrigiere Projekt-Berechtigungen für kiosk-User..." # Prüfe ob kiosk User existiert if ! id "$KIOSK_USER" &>/dev/null; then warning "⚠️ Kiosk-User '$KIOSK_USER' existiert nicht - erstelle ihn zuerst" create_kiosk_user fi local kiosk_home="/home/$KIOSK_USER" # Erstelle Entwicklungs-/Arbeitsverzeichnis im kiosk home local kiosk_project_dir="$kiosk_home/manage-your-printer" progress "Erstelle kiosk-Arbeitsverzeichnis: $kiosk_project_dir" if [ ! -d "$kiosk_project_dir" ]; then mkdir -p "$kiosk_project_dir" 2>/dev/null || true fi # Kopiere/Synchronisiere Projekt-Dateien zum kiosk-Verzeichnis progress "Synchronisiere Projekt-Dateien für kiosk-User..." # Verwende rsync wenn verfügbar, sonst cp if command -v rsync >/dev/null 2>&1; then rsync -av --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' \ --exclude='instance/ssl/*' --exclude='logs/*' \ "$CURRENT_DIR/" "$kiosk_project_dir/" 2>/dev/null || { warning "⚠️ rsync fehlgeschlagen - verwende cp als Fallback" cp -r "$CURRENT_DIR"/* "$kiosk_project_dir/" 2>/dev/null || true } else cp -r "$CURRENT_DIR"/* "$kiosk_project_dir/" 2>/dev/null || true fi # Setze kiosk als Besitzer des Arbeitsverzeichnisses progress "Setze kiosk-User als Besitzer des Arbeitsverzeichnisses..." chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir" 2>/dev/null || warning "⚠️ Ownership konnte nicht vollständig gesetzt werden" # Spezielle Berechtigungen für verschiedene Bereiche progress "Konfiguriere spezielle Berechtigungen..." # node_modules: kiosk User soll vollen Zugriff haben if [ -d "$kiosk_project_dir/node_modules" ]; then chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/node_modules" 2>/dev/null || true chmod -R 755 "$kiosk_project_dir/node_modules" 2>/dev/null || true success "✅ node_modules Berechtigungen für kiosk-User gesetzt" fi # package.json und package-lock.json: kiosk User soll schreiben können for file in package.json package-lock.json; do if [ -f "$kiosk_project_dir/$file" ]; then chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/$file" 2>/dev/null || true chmod 664 "$kiosk_project_dir/$file" 2>/dev/null || true fi done # logs Verzeichnis: kiosk User soll schreiben können if [ -d "$kiosk_project_dir/logs" ]; then chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/logs" 2>/dev/null || true chmod -R 755 "$kiosk_project_dir/logs" 2>/dev/null || true fi # uploads Verzeichnis: kiosk User soll schreiben können if [ -d "$kiosk_project_dir/uploads" ]; then chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/uploads" 2>/dev/null || true chmod -R 755 "$kiosk_project_dir/uploads" 2>/dev/null || true fi # Auch die Original node_modules in APP_DIR korrigieren progress "Korrigiere node_modules Berechtigungen in $APP_DIR..." if [ -d "$APP_DIR/node_modules" ]; then # Erstelle kiosk-Gruppe und füge root hinzu für geteilten Zugriff groupadd -f kiosk-shared 2>/dev/null || true usermod -a -G kiosk-shared root 2>/dev/null || true usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true # Setze Gruppe auf kiosk-shared für geteilten Zugriff chgrp -R kiosk-shared "$APP_DIR/node_modules" 2>/dev/null || true chmod -R 775 "$APP_DIR/node_modules" 2>/dev/null || true success "✅ node_modules geteilte Berechtigungen gesetzt" fi # Erstelle npm-Konfiguration für kiosk User progress "Konfiguriere npm für kiosk-User..." if [ ! -d "$kiosk_home/.npm" ]; then mkdir -p "$kiosk_home/.npm" 2>/dev/null || true chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npm" 2>/dev/null || true fi # Erstelle .npmrc für kiosk User cat > "$kiosk_home/.npmrc" << 'NPMRCEOF' # npm-Konfiguration für kiosk User fund=false audit-level=moderate progress=false loglevel=warn cache=/home/kiosk/.npm prefix=/home/kiosk/.npm-global NPMRCEOF chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npmrc" 2>/dev/null || true # npm global Verzeichnis erstellen mkdir -p "$kiosk_home/.npm-global" 2>/dev/null || true chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npm-global" 2>/dev/null || true # X11-Autorisierung sicherstellen progress "Sicherstelle X11-Autorisierung für kiosk-User..." if [ ! -f "$kiosk_home/.Xauthority" ]; then touch "$kiosk_home/.Xauthority" chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority" chmod 600 "$kiosk_home/.Xauthority" success "✅ .Xauthority Datei erstellt" fi # DISPLAY-Variable in bashrc sicherstellen if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then cat >> "$kiosk_home/.bashrc" << 'EOF' # X11 Display Konfiguration export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority EOF chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" success "✅ X11-Variablen zu .bashrc hinzugefügt" fi success "✅ Projekt-Berechtigungen für kiosk-User konfiguriert" info " 📁 Kiosk-Arbeitsverzeichnis: $kiosk_project_dir" info " 👤 Besitzer: $KIOSK_USER" info " 🔧 npm-Konfiguration erstellt" } create_permission_fix_script() { log "=== ERSTELLE BERECHTIGEN-REPARATUR-SKRIPT ===" local fix_script="$CURRENT_DIR/fix-permissions.sh" progress "Erstelle automatisches Berechtigen-Reparatur-Skript..." cat > "$fix_script" << 'FIXSCRIPTEOF' #!/bin/bash # =================================================================== # MYP Berechtigen-Reparatur-Skript # Behebt Berechtigungsprobleme nach npm install als root # Kann von jedem User ausgeführt werden # =================================================================== set -euo pipefail KIOSK_USER="kiosk" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Farben für Ausgabe RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${GREEN}[$(date '+%H:%M:%S')] $1${NC}" } warning() { echo -e "${YELLOW}[WARNUNG] $1${NC}" } error() { echo -e "${RED}[FEHLER] $1${NC}" exit 1 } info() { echo -e "${BLUE}[INFO] $1${NC}" } # Prüfe root-Berechtigung if [ "$EUID" -ne 0 ]; then error "Dieses Skript muss als Root ausgeführt werden: sudo $0" fi log "=== MYP BERECHTIGEN-REPARATUR ===" log "Arbeitsverzeichnis: $SCRIPT_DIR" # Prüfe ob kiosk User existiert if ! id "$KIOSK_USER" &>/dev/null; then error "Kiosk-User '$KIOSK_USER' existiert nicht!" fi # Lösche node_modules wenn vorhanden (für saubere Neuinstallation) if [ -d "$SCRIPT_DIR/node_modules" ]; then log "Entferne bestehende node_modules für saubere Neuinstallation..." rm -rf "$SCRIPT_DIR/node_modules" fi # Erstelle kiosk-shared Gruppe für geteilten Zugriff log "Erstelle geteilte Berechtigen-Gruppe..." groupadd -f kiosk-shared 2>/dev/null || true usermod -a -G kiosk-shared root 2>/dev/null || true usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true # Führe npm install als kiosk User aus log "Führe npm install als kiosk-User aus..." if [ -f "$SCRIPT_DIR/package.json" ]; then # Wechsle zu kiosk User für npm install sudo -u "$KIOSK_USER" bash -c " cd '$SCRIPT_DIR' export HOME=/home/$KIOSK_USER if npm install --no-optional --no-audit --no-fund 2>/dev/null; then echo 'npm install erfolgreich (Standard)' elif npm install --legacy-peer-deps --no-optional 2>/dev/null; then echo 'npm install erfolgreich (Legacy-Modus)' elif npm install --force 2>/dev/null; then echo 'npm install erfolgreich (Force-Modus)' else echo 'npm install fehlgeschlagen' exit 1 fi " if [ $? -eq 0 ]; then log "✅ npm install als kiosk-User erfolgreich" else warning "⚠️ npm install als kiosk-User fehlgeschlagen - versuche als root mit Berechtigen-Korrektur" # Fallback: npm install als root, dann Berechtigungen korrigieren if npm install --no-optional --no-audit --no-fund 2>/dev/null; then log "npm install als root erfolgreich - korrigiere Berechtigungen..." # Korrigiere node_modules Berechtigungen if [ -d "$SCRIPT_DIR/node_modules" ]; then chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/node_modules" 2>/dev/null || true chmod -R 775 "$SCRIPT_DIR/node_modules" 2>/dev/null || true log "✅ node_modules Berechtigungen korrigiert" fi else error "npm install auch als root fehlgeschlagen" fi fi else warning "Keine package.json gefunden" fi # Korrigiere allgemeine Projekt-Berechtigungen log "Korrigiere allgemeine Projekt-Berechtigungen..." # package.json und package-lock.json for file in package.json package-lock.json; do if [ -f "$SCRIPT_DIR/$file" ]; then chown "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/$file" 2>/dev/null || true chmod 664 "$SCRIPT_DIR/$file" 2>/dev/null || true fi done # logs Verzeichnis if [ -d "$SCRIPT_DIR/logs" ]; then chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/logs" 2>/dev/null || true chmod -R 775 "$SCRIPT_DIR/logs" 2>/dev/null || true fi # uploads Verzeichnis if [ -d "$SCRIPT_DIR/uploads" ]; then chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/uploads" 2>/dev/null || true chmod -R 775 "$SCRIPT_DIR/uploads" 2>/dev/null || true fi # static Verzeichnis (falls der User dort Änderungen macht) if [ -d "$SCRIPT_DIR/static" ]; then chgrp -R kiosk-shared "$SCRIPT_DIR/static" 2>/dev/null || true chmod -R 775 "$SCRIPT_DIR/static" 2>/dev/null || true fi # X11-Autorisierung für kiosk-User sicherstellen log "Sicherstelle X11-Autorisierung..." kiosk_home="/home/$KIOSK_USER" if [ ! -f "$kiosk_home/.Xauthority" ]; then touch "$kiosk_home/.Xauthority" chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority" chmod 600 "$kiosk_home/.Xauthority" log "✅ .Xauthority Datei erstellt" fi # DISPLAY-Variable in bashrc sicherstellen if [ -f "$kiosk_home/.bashrc" ] && ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then cat >> "$kiosk_home/.bashrc" << 'BASHRCEOF' # X11 Display Konfiguration export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority BASHRCEOF chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" log "✅ X11-Variablen zu .bashrc hinzugefügt" fi log "✅ Berechtigen-Reparatur abgeschlossen" info "" info "📋 Zusammenfassung:" info " - node_modules gehört jetzt dem kiosk-User" info " - Geteilte kiosk-shared Gruppe erstellt" info " - Entwicklungs-Dateien für kiosk-User beschreibbar" info "" info "🔧 Verwendung:" info " - Als kiosk-User: cd $SCRIPT_DIR && npm install" info " - Als root bei Problemen: sudo $0" info "" FIXSCRIPTEOF # Mache Skript ausführbar chmod +x "$fix_script" 2>/dev/null || warning "⚠️ Konnte fix-permissions.sh nicht ausführbar machen" success "✅ Berechtigen-Reparatur-Skript erstellt: $fix_script" info " 💡 Verwendung nach Setup: sudo ./fix-permissions.sh" # Erstelle zusätzliches X11-Fix-Skript local x11_fix_script="$CURRENT_DIR/fix-x11.sh" progress "Erstelle X11-Reparatur-Skript..." cat > "$x11_fix_script" << 'X11FIXSCRIPTEOF' #!/bin/bash # =================================================================== # MYP X11-Reparatur-Skript # Behebt X11/.Xauthority-Probleme für kiosk-User # Kann als root oder kiosk-User ausgeführt werden # =================================================================== set -euo pipefail KIOSK_USER="kiosk" # Farben für Ausgabe RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${GREEN}[$(date '+%H:%M:%S')] $1${NC}" } warning() { echo -e "${YELLOW}[WARNUNG] $1${NC}" } error() { echo -e "${RED}[FEHLER] $1${NC}" exit 1 } info() { echo -e "${BLUE}[INFO] $1${NC}" } log "=== MYP X11-REPARATUR ===" # Prüfe ob kiosk User existiert if ! id "$KIOSK_USER" &>/dev/null; then error "Kiosk-User '$KIOSK_USER' existiert nicht!" fi kiosk_home="/home/$KIOSK_USER" # Stoppe laufende X11-Prozesse log "Stoppe laufende X11-Prozesse..." pkill -f "startx" 2>/dev/null || true pkill -f "X " 2>/dev/null || true pkill -f "Xorg" 2>/dev/null || true pkill -f "chromium" 2>/dev/null || true sleep 2 # Bereinige alte X11-Session-Dateien log "Bereinige alte X11-Session-Dateien..." rm -f /tmp/.X0-lock 2>/dev/null || true rm -f /tmp/.X11-unix/X0 2>/dev/null || true # X11-Autorisierung neu erstellen log "Erstelle X11-Autorisierung neu..." # Entferne alte .Xauthority if [ -f "$kiosk_home/.Xauthority" ]; then rm -f "$kiosk_home/.Xauthority" fi # Erstelle neue .Xauthority touch "$kiosk_home/.Xauthority" # Setze korrekte Berechtigungen (funktioniert sowohl als root als auch als kiosk) if [ "$EUID" -eq 0 ]; then chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority" fi chmod 600 "$kiosk_home/.Xauthority" log "✅ .Xauthority neu erstellt" # Prüfe und korrigiere .bashrc log "Prüfe X11-Umgebungsvariablen..." if [ -f "$kiosk_home/.bashrc" ]; then if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then log "Füge X11-Variablen zu .bashrc hinzu..." cat >> "$kiosk_home/.bashrc" << 'BASHEOF2' # X11 Display Konfiguration export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority BASHEOF2 if [ "$EUID" -eq 0 ]; then chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc" fi log "✅ X11-Variablen hinzugefügt" else log "✅ X11-Variablen bereits konfiguriert" fi else warning "⚠️ .bashrc nicht gefunden" fi # Erstelle X11-Test-Skript log "Erstelle X11-Test-Skript..." cat > "$kiosk_home/test-x11.sh" << 'TESTEOF' #!/bin/bash # X11-Test für kiosk-User export DISPLAY=:0.0 export XAUTHORITY=/home/kiosk/.Xauthority echo "=== X11-Test ===" echo "DISPLAY: $DISPLAY" echo "XAUTHORITY: $XAUTHORITY" echo "" if [ -f "$XAUTHORITY" ]; then echo "✅ .Xauthority existiert" ls -la "$XAUTHORITY" else echo "❌ .Xauthority fehlt" exit 1 fi echo "" echo "Teste X11-Verbindung..." if command -v xset >/dev/null 2>&1; then if xset q >/dev/null 2>&1; then echo "✅ X11-Server erreichbar" xset q | head -3 else echo "❌ X11-Server nicht erreichbar" echo "Versuche X11-Server zu starten..." startx /home/kiosk/.xinitrc -- :0 vt1 & sleep 5 if xset q >/dev/null 2>&1; then echo "✅ X11-Server nach Start erreichbar" else echo "❌ X11-Server konnte nicht gestartet werden" exit 1 fi fi else echo "⚠️ xset nicht verfügbar - kann X11 nicht testen" fi echo "" echo "✅ X11-Test abgeschlossen" TESTEOF chmod +x "$kiosk_home/test-x11.sh" if [ "$EUID" -eq 0 ]; then chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/test-x11.sh" fi log "✅ X11-Reparatur abgeschlossen" info "" info "📋 Was wurde behoben:" info " - Alte .Xauthority entfernt und neu erstellt" info " - X11-Umgebungsvariablen konfiguriert" info " - X11-Test-Skript erstellt" info "" info "🔧 Nächste Schritte:" info " - Als kiosk-User einloggen: su - kiosk" info " - X11 testen: ./test-x11.sh" info " - Kiosk-Modus starten: ./start-x11.sh" info "" info "💡 Bei weiteren Problemen:" info " - Neustart: sudo reboot" info " - Manual X11 start: startx" info "" X11FIXSCRIPTEOF chmod +x "$x11_fix_script" 2>/dev/null || warning "⚠️ Konnte fix-x11.sh nicht ausführbar machen" success "✅ X11-Reparatur-Skript erstellt: $x11_fix_script" info " 💡 Verwendung bei X11-Problemen: sudo ./fix-x11.sh" } 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 # WICHTIG: Korrigiere Berechtigungen nach npm install progress "Korrigiere npm-Berechtigungen für kiosk-User..." if [ -d "$APP_DIR/node_modules" ]; then # Erstelle geteilte Gruppe wenn noch nicht vorhanden groupadd -f kiosk-shared 2>/dev/null || true usermod -a -G kiosk-shared root 2>/dev/null || true if id "$KIOSK_USER" &>/dev/null; then usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true chown -R "$KIOSK_USER:kiosk-shared" "$APP_DIR/node_modules" 2>/dev/null || true success "✅ node_modules Berechtigungen für kiosk-User korrigiert" else warning "⚠️ Kiosk-User nicht gefunden - Berechtigungen werden später korrigiert" fi chmod -R 775 "$APP_DIR/node_modules" 2>/dev/null || true fi cd "$CURRENT_DIR" else info "Keine package.json gefunden - überspringe npm-Installation" fi log "✅ NPM-Abhängigkeiten verarbeitet" } # =========================== SSL-ZERTIFIKAT GENERIERUNG (ENTFERNT) =========================== # SSL-Zertifikate nicht mehr benötigt - verwende HTTP statt HTTPS # =========================== ROBUSTE SYSTEMD-SERVICES INSTALLATION =========================== install_systemd_services() { log "=== ROBUSTE SYSTEMD-SERVICES INSTALLATION ===" # Prüfe ob systemd verfügbar ist if ! command -v systemctl >/dev/null 2>&1; then warning "⚠️ systemctl nicht gefunden - überspringe Service-Installation" info " → System läuft möglicherweise ohne systemd (WSL, Docker, etc.)" return fi # Validiere systemd-Verzeichnis if [ ! -d "$SYSTEMD_DIR" ]; then warning "⚠️ systemd-Verzeichnis nicht gefunden: $SYSTEMD_DIR" info " → Überspringe Service-Installation" return fi progress "Validiere und kopiere Service-Dateien..." # Definiere Service-Dateien mit Priorität local essential_services=( "$HTTP_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 ===" # Prüfe ob systemd verfügbar ist if ! command -v systemctl >/dev/null 2>&1; then warning "⚠️ systemctl nicht gefunden - überspringe Service-Aktivierung" return fi # Service-Status tracking local successful_services=0 local failed_services=0 # HTTP-Backend-Service (kritisch) progress "Aktiviere und starte HTTP-Backend-Service (kritisch)..." if systemctl enable "$HTTP_SERVICE_NAME" 2>/dev/null; then success "✅ HTTP-Backend-Service erfolgreich aktiviert" if systemctl start "$HTTP_SERVICE_NAME" 2>/dev/null; then success "✅ HTTP-Backend-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 "$HTTP_SERVICE_NAME"; then success "✅ HTTP-Backend-Service läuft stabil nach ${elapsed}s" ((successful_services++)) break fi sleep $check_interval elapsed=$((elapsed + check_interval)) progress "Warte auf HTTP-Backend-Service Startup... (${elapsed}/${startup_timeout}s)" done if [ $elapsed -ge $startup_timeout ]; then error "❌ HTTP-Backend-Service Timeout nach ${startup_timeout}s - Service nicht verfügbar" # Debugging-Informationen info "HTTP-Backend-Service Status-Debug:" systemctl status "$HTTP_SERVICE_NAME" --no-pager -l || true journalctl -u "$HTTP_SERVICE_NAME" --no-pager -n 10 || true ((failed_services++)) fi else error "❌ HTTP-Backend-Service konnte nicht gestartet werden" ((failed_services++)) fi else error "❌ HTTP-Backend-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 ===" echo "" echo -e "${BLUE}🔍 Führe System-Tests durch...${NC}" echo "" local test_errors=0 local test_warnings=0 # Test 1: Service-Status prüfen progress "Teste Service-Status..." if systemctl is-active --quiet "$HTTP_SERVICE_NAME"; then success "✅ HTTP-Backend-Service ist aktiv" else warning "⚠️ HTTP-Backend-Service ist nicht aktiv" ((test_warnings++)) # Debug-Informationen info "Service-Status Debug:" systemctl status "$HTTP_SERVICE_NAME" --no-pager -l || true fi # Test 2: Port-Verfügbarkeit progress "Teste Port-Verfügbarkeit..." if ss -tlnp | grep -q ":5000 "; then success "✅ Port 5000 ist geöffnet" else warning "⚠️ Port 5000 ist nicht geöffnet" ((test_warnings++)) fi # Test 3: HTTP-Backend-Verbindung (robust mit mehreren Methoden) progress "Teste HTTP-Backend-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 -s --connect-timeout 3 --max-time 8 "$HTTP_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 --timeout=3 --tries=1 "$HTTP_URL" -O /dev/null 2>/dev/null; then connection_successful=true break fi fi # Methode 3: nc als direkter Port-Test if command -v nc >/dev/null 2>&1; then if echo "GET / HTTP/1.0" | nc -w 3 localhost 5000 2>/dev/null | grep -q "HTTP"; then connection_successful=true break fi fi progress "Warte auf HTTP-Backend... ($attempt/$max_attempts)" sleep 3 ((attempt++)) done if [ "$connection_successful" = true ]; then success "✅ HTTP-Backend erreichbar unter $HTTP_URL" # Erweiterte Verbindungstests progress "Führe erweiterte HTTP-Tests durch..." # Test Antwortzeit local response_time=$(curl -s -w "%{time_total}" -o /dev/null "$HTTP_URL" 2>/dev/null || echo "timeout") if [ "$response_time" != "timeout" ]; then info "🕐 HTTP Antwortzeit: ${response_time}s" # Bewerte Antwortzeit (ohne bc für bessere Kompatibilität) local response_ms=$(echo "$response_time * 1000" | awk '{print int($1)}' 2>/dev/null || echo "9999") if [ "$response_ms" -lt 2000 ]; then success "✅ Gute Antwortzeit" elif [ "$response_ms" -lt 5000 ]; then info "ℹ️ Akzeptable Antwortzeit" else warning "⚠️ Langsame Antwortzeit" ((test_warnings++)) fi fi # Test HTTP-Status local http_status=$(curl -s -o /dev/null -w "%{http_code}" "$HTTP_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 "❌ HTTP-Backend nicht erreichbar nach $max_attempts Versuchen" ((test_errors++)) # Debugging-Informationen info "HTTP-Debug Informationen:" netstat -tlnp | grep ":5000" || info "Port 5000 nicht gefunden" ss -tlnp | grep ":5000" || info "Port 5000 nicht in ss gefunden" fi # Test 4: HTTP-Header und Content-Type Prüfung progress "Teste HTTP-Header und Content-Type..." if [ "$connection_successful" = true ]; then # Test Content-Type Header local content_type=$(curl -s -I "$HTTP_URL" 2>/dev/null | grep -i "content-type:" | head -1 | cut -d: -f2 | tr -d ' \r\n' || echo "unknown") if [[ "$content_type" == *"text/html"* ]]; then success "✅ Korrekte HTML-Antwort erkannt" else info "ℹ️ Content-Type: $content_type" fi # Test Server Header local server_header=$(curl -s -I "$HTTP_URL" 2>/dev/null | grep -i "server:" | head -1 | cut -d: -f2 | tr -d ' \r\n' || echo "unknown") if [ "$server_header" != "unknown" ]; then info "🖥️ Server: $server_header" fi else info "ℹ️ HTTP-Header Test übersprungen (Backend nicht erreichbar)" 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 echo "" echo -e "${CYAN}=================================================================${NC}" echo -e "${CYAN} SYSTEM-TEST ERGEBNISSE${NC}" echo -e "${CYAN}=================================================================${NC}" echo "" echo -e "${BLUE}📊 Test-Zusammenfassung:${NC}" echo -e " ❌ Fehler: $test_errors" echo -e " ⚠️ Warnungen: $test_warnings" echo "" if [ $test_errors -eq 0 ] && [ $test_warnings -eq 0 ]; then echo -e "${GREEN}✅ Alle System-Tests erfolgreich!${NC}" echo -e "${GREEN} → System vollständig funktionsfähig${NC}" echo "" return 0 elif [ $test_errors -eq 0 ]; then echo -e "${YELLOW}⚠️ System-Tests mit $test_warnings Warnungen abgeschlossen${NC}" echo -e "${YELLOW} → System grundsätzlich funktionsfähig${NC}" echo "" return 0 else echo -e "${RED}❌ System-Tests mit $test_errors Fehlern fehlgeschlagen${NC}" echo -e "${RED} → System möglicherweise nicht funktionsfähig${NC}" echo "" 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 (verwendet /tmp für Logs) 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 # Berechtigungen für kiosk-User korrigieren fix_project_permissions create_permission_fix_script # 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 "🌐 HTTP-Backend sollte verfügbar sein: $HTTP_URL" info "⚙️ Manuelle App-Start Alternative: cd /opt/myp && python3 app.py --production" # Fehler-Zusammenfassung anzeigen show_error_summary # Finale Status-Anzeige echo "" echo -e "${GREEN}=================================================================${NC}" echo -e "${GREEN} INSTALLATION ERFOLGREICH ABGESCHLOSSEN!${NC}" echo -e "${GREEN}=================================================================${NC}" echo "" echo -e "${BLUE}📋 Was wurde installiert:${NC}" echo -e " ✅ System-Updates und Tools" echo -e " ✅ Python 3 und pip" echo -e " ✅ Node.js und npm" echo -e " ✅ SSL-Zertifikate" echo -e " ✅ Anwendung deployed nach: $APP_DIR" echo -e " ✅ Systemd-Services installiert" echo "" echo -e "${YELLOW}🚀 Nächste Schritte:${NC}" echo -e " 1. Testen Sie die Anwendung:" echo -e " ${CYAN}cd $APP_DIR && python3 app.py${NC}" echo -e " 2. Oder prüfen Sie den Service:" echo -e " ${CYAN}sudo systemctl status $HTTP_SERVICE_NAME${NC}" echo -e " 3. Zugriff über Browser:" echo -e " ${CYAN}$HTTP_URL${NC}" echo "" echo -e "${GREEN}✅ System bereit für manuelle Tests!${NC}" echo -e "${GREEN}=================================================================${NC}" } install_full_production_system() { # Logging initialisieren (verwendet /tmp für Logs) 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 # Berechtigungen für kiosk-User korrigieren fix_project_permissions create_permission_fix_script 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 configure_x11_for_raspberry_pi # Performance-Optimierungen für Raspberry Pi Webapp optimize_webapp_performance # Static Assets nur optimieren wenn App deployed wurde if [ -d "$APP_DIR" ] && [ -d "$APP_DIR/static" ]; then optimize_static_assets else info "⏭️ Static Asset Optimierung übersprungen - App noch nicht deployed" fi # 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 " 🌐 HTTP-Backend: $HTTP_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 # Finale Status-Anzeige für Vollinstallation echo "" echo -e "${GREEN}=================================================================${NC}" echo -e "${GREEN} VOLLSTÄNDIGE INSTALLATION ERFOLGREICH ABGESCHLOSSEN!${NC}" echo -e "${GREEN}=================================================================${NC}" echo "" echo -e "${BLUE}📋 Was wurde installiert:${NC}" echo -e " ✅ Komplettes Produktionssystem" echo -e " ✅ Kiosk-Modus konfiguriert" echo -e " ✅ Remote-Zugang (SSH & RDP)" echo -e " ✅ Firewall konfiguriert" echo -e " ✅ Automatischer Start beim Boot" echo "" echo -e "${YELLOW}🔐 Zugangsdaten:${NC}" echo -e " SSH: user:raspberry (Port 22)" echo -e " RDP: root:744563017196A (Port 3389)" echo "" echo -e "${RED}⚠️ WICHTIG: Neustart erforderlich!${NC}" echo -e " ${CYAN}sudo reboot${NC}" echo "" echo -e "${GREEN}✅ Produktionssystem vollständig installiert!${NC}" echo -e "${GREEN}=================================================================${NC}" } # =========================== 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 ===" # Stelle sicher, dass APP_DIR existiert if [ -z "$APP_DIR" ] || [ ! -d "$APP_DIR" ]; then warning "⚠️ APP_DIR nicht definiert oder nicht vorhanden - überspringe Asset-Optimierung" return fi if [ ! -d "$APP_DIR/static" ]; then warning "⚠️ Static-Ordner nicht gefunden: $APP_DIR/static - überspringe Asset-Optimierung" return fi progress "Analysiere und optimiere CSS/JS Dateien..." # Speichere aktuelles Verzeichnis local original_dir=$(pwd) # Wechsle zu static Verzeichnis cd "$APP_DIR/static" 2>/dev/null || { warning "⚠️ Konnte nicht zu $APP_DIR/static wechseln" return } # 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 # Zurück zum Original-Verzeichnis cd "$original_dir" 2>/dev/null || cd "$CURRENT_DIR" 2>/dev/null || true 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() { # Stelle sicher, dass wir im richtigen Verzeichnis sind cd "$CURRENT_DIR" 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/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/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/install-summary.txt" ] && echo -e " 📊 Zusammenfassung: logs/install-summary.txt" fi exit 0 ;; *) echo -e "${RED}Ungültige Auswahl. Bitte wählen Sie 1-3.${NC}" ;; esac done } # Skript starten main "$@"