4194 lines
146 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 "$@"