2884 lines
97 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 HTTPS_SERVICE_NAME="myp-https"
readonly KIOSK_SERVICE_NAME="myp-kiosk"
readonly WATCHDOG_SERVICE_NAME="kiosk-watchdog"
readonly WATCHDOG_PYTHON_SERVICE_NAME="kiosk-watchdog-python"
readonly FIREWALL_SERVICE_NAME="myp-firewall"
readonly KIOSK_USER="kiosk"
readonly CURRENT_DIR="$(pwd)"
readonly INSTALL_LOG="/var/log/myp-install.log"
readonly HTTPS_PORT="443"
readonly HTTPS_URL="https://localhost:${HTTPS_PORT}"
readonly SYSTEMD_DIR="$CURRENT_DIR/systemd"
readonly SYSTEM_SYSTEMD_DIR="/etc/systemd/system"
# Retry-Konfiguration
readonly MAX_RETRIES=3
readonly RETRY_DELAY=5
# Farben für Ausgabe
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly PURPLE='\033[0;35m'
readonly CYAN='\033[0;36m'
readonly NC='\033[0m'
# =========================== VERBESSERTE LOGGING-FUNKTIONEN ===========================
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$INSTALL_LOG"
}
error() {
echo -e "${RED}[FEHLER] $1${NC}" | tee -a "$INSTALL_LOG"
exit 1
}
warning() {
echo -e "${YELLOW}[WARNUNG] $1${NC}" | tee -a "$INSTALL_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() {
echo -e "${BLUE}[DEBUG] $1${NC}" >> "$INSTALL_LOG"
}
# =========================== 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..."
sleep $RETRY_DELAY
fi
done
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
local ram_mb=$(free -m | awk '/^Mem:/{print $2}')
progress "Verfügbarer RAM: ${ram_mb}MB"
if [ -n "$ram_mb" ] && [ "$ram_mb" -eq "$ram_mb" ] 2>/dev/null && [ "$ram_mb" -lt 512 ]; then
warning "⚠️ Wenig RAM verfügbar (${ram_mb}MB) - Installation könnte langsam sein"
elif [ -n "$ram_mb" ] && [ "$ram_mb" -eq "$ram_mb" ] 2>/dev/null; then
success "✅ Ausreichend RAM verfügbar (${ram_mb}MB)"
else
warning "⚠️ RAM-Größe konnte nicht ermittelt werden"
fi
# Festplattenplatz prüfen
local disk_free_gb=$(df / | awk 'NR==2{printf "%.1f", $4/1024/1024}')
progress "Verfügbarer Festplattenplatz: ${disk_free_gb}GB"
# Konvertiere zu Ganzzahl für Vergleich (GB * 10 für eine Dezimalstelle)
local disk_free_int=$(echo "$disk_free_gb * 10" | bc 2>/dev/null | cut -d. -f1)
local min_required_int=20 # 2.0 GB * 10
if [ -z "$disk_free_int" ] || [ "$disk_free_int" -lt "$min_required_int" ]; then
warning "⚠️ Wenig Festplattenplatz verfügbar (${disk_free_gb}GB)"
else
success "✅ Ausreichend Festplattenplatz verfügbar (${disk_free_gb}GB)"
fi
# CPU prüfen
local cpu_count=$(nproc)
local cpu_model=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
progress "CPU: $cpu_count Kern(e) - $cpu_model"
log "✅ System-Ressourcen validiert"
}
check_debian_system() {
if [ ! -f /etc/debian_version ]; then
error "Dieses Skript ist nur für Debian/Raspbian-Systeme geeignet!"
fi
local debian_version=$(cat /etc/debian_version 2>/dev/null || echo "Unbekannt")
log "✅ Debian/Raspbian-System erkannt (Version: $debian_version)"
# Prüfe auf Raspberry Pi
if [ -f /proc/device-tree/model ]; then
local pi_model=$(cat /proc/device-tree/model 2>/dev/null | tr -d '\0' || echo "Unbekannt")
info "Raspberry Pi Modell: $pi_model"
# Raspberry Pi spezifische Optimierungen
if [[ "$pi_model" =~ "Raspberry Pi" ]]; then
progress "Aktiviere Raspberry Pi spezifische Optimierungen..."
export RASPBERRY_PI_DETECTED=1
fi
fi
# Architektur prüfen
local arch=$(uname -m)
info "System-Architektur: $arch"
# Kernel-Version prüfen
local kernel=$(uname -r)
info "Kernel-Version: $kernel"
}
check_internet_connection() {
progress "Prüfe Internetverbindung (erweiterte Methoden)..."
local connection_ok=false
local test_method=""
# Methode 1: DNS-Auflösung zuerst (schnellster Test)
progress "Teste DNS-Auflösung..."
local dns_hosts=("google.com" "cloudflare.com" "github.com" "8.8.8.8")
for host in "${dns_hosts[@]}"; do
if nslookup "$host" >/dev/null 2>&1; then
connection_ok=true
test_method="DNS-Auflösung (nslookup: $host)"
break
elif getent hosts "$host" >/dev/null 2>&1; then
connection_ok=true
test_method="DNS-Auflösung (getent: $host)"
break
fi
done
# Methode 2: HTTP/HTTPS-Tests
if [ "$connection_ok" = false ]; then
progress "Teste HTTP/HTTPS-Verbindungen..."
local http_urls=("http://detectportal.firefox.com/success.txt" "https://www.google.com" "http://httpbin.org/get")
for url in "${http_urls[@]}"; do
if command -v curl >/dev/null 2>&1; then
if curl -s --connect-timeout 10 --max-time 15 "$url" >/dev/null 2>&1; then
connection_ok=true
test_method="HTTP/HTTPS (curl: $url)"
break
fi
elif command -v wget >/dev/null 2>&1; then
if wget -q --timeout=10 --tries=1 "$url" -O /dev/null 2>/dev/null; then
connection_ok=true
test_method="HTTP/HTTPS (wget: $url)"
break
fi
fi
done
fi
# Methode 3: APT-Repository-Test
if [ "$connection_ok" = false ]; then
progress "Teste APT-Repository-Zugang..."
if apt-get update -qq 2>/dev/null; then
connection_ok=true
test_method="APT-Repository-Zugang"
fi
fi
# Ergebnis-Bewertung
if [ "$connection_ok" = true ]; then
success "✅ Internetverbindung verfügbar"
info " 🔍 Erkannt via: $test_method"
# Zusätzliche Informationen
if command -v curl >/dev/null 2>&1; then
local external_ip=$(curl -s --connect-timeout 5 ifconfig.me 2>/dev/null || curl -s --connect-timeout 5 ipinfo.io/ip 2>/dev/null || echo "Unbekannt")
if [ "$external_ip" != "Unbekannt" ]; then
info " 🌐 Externe IP: $external_ip"
fi
fi
else
warning "⚠️ Keine Internetverbindung erkannt"
info " → Installation wird fortgesetzt, aber Downloads könnten fehlschlagen"
warning " → Bitte prüfen Sie die Netzwerkverbindung!"
fi
}
# =========================== ROBUSTE SYSTEM-VORBEREITUNG ===========================
update_system() {
log "=== ROBUSTE SYSTEM-UPDATE ==="
progress "Konfiguriere APT für bessere Zuverlässigkeit..."
# APT-Konfiguration optimieren
cat > /etc/apt/apt.conf.d/99myp-optimized << 'EOF'
APT::Acquire::Retries "3";
APT::Acquire::http::Timeout "30";
APT::Acquire::https::Timeout "30";
APT::Acquire::ftp::Timeout "30";
APT::Install-Recommends "false";
APT::Install-Suggests "false";
Dpkg::Options {
"--force-confdef";
"--force-confold";
}
EOF
# Repository-Listen korrigieren falls nötig
progress "Validiere APT-Repositories..."
if [ -f /etc/apt/sources.list ]; then
# Backup erstellen
cp /etc/apt/sources.list /etc/apt/sources.list.backup
# Prüfe auf problematische Einträge
if grep -q "deb-src" /etc/apt/sources.list; then
sed -i 's/^deb-src/#deb-src/g' /etc/apt/sources.list
log "✅ Source-Repositories deaktiviert (nicht benötigt)"
fi
fi
progress "Aktualisiere Paketlisten mit Retry..."
retry_command "apt-get update" "APT Update"
progress "Führe System-Upgrade durch..."
retry_command "DEBIAN_FRONTEND=noninteractive apt-get upgrade -y" "System Upgrade"
progress "Installiere essenzielle System-Tools..."
# Grundlegende Tools in optimierter Reihenfolge
local essential_packages=(
"ca-certificates"
"gnupg"
"curl"
"wget"
"git"
"nano"
"htop"
"rsync"
"unzip"
"sudo"
"systemd"
"lsb-release"
"apt-transport-https"
"software-properties-common"
"bc"
"dbus"
"systemd-timesyncd"
)
for package in "${essential_packages[@]}"; do
apt_install_retry "$package"
done
# Zeitserver synchronisieren
progress "Synchronisiere Systemzeit..."
systemctl enable systemd-timesyncd 2>/dev/null || true
systemctl start systemd-timesyncd 2>/dev/null || true
log "✅ Robustes System-Update abgeschlossen"
}
# =========================== VERBESSERTE PYTHON-INSTALLATION ===========================
install_python_dependencies() {
log "=== ROBUSTE PYTHON-INSTALLATION ==="
progress "Installiere Python 3 und Build-Abhängigkeiten..."
local python_packages=(
"python3"
"python3-pip"
"python3-dev"
"python3-setuptools"
"python3-venv"
"python3-wheel"
"build-essential"
"libssl-dev"
"libffi-dev"
"libbz2-dev"
"libreadline-dev"
"libsqlite3-dev"
"libncurses5-dev"
"libncursesw5-dev"
"zlib1g-dev"
"sqlite3"
)
for package in "${python_packages[@]}"; do
apt_install_retry "$package"
done
# Python-Version validieren
progress "Validiere Python-Installation..."
local python_version=$(python3 --version 2>&1 | cut -d' ' -f2)
log "✅ Python Version: $python_version"
# pip konfigurieren und aktualisieren
progress "Konfiguriere pip für bessere Zuverlässigkeit..."
# Root pip-Konfiguration
mkdir -p /root/.pip
cat > /root/.pip/pip.conf << 'EOF'
[global]
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
cert = /etc/ssl/certs/ca-certificates.crt
timeout = 120
retries = 5
no-cache-dir = false
disable-pip-version-check = true
no-warn-script-location = true
break-system-packages = true
[install]
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
user = false
break-system-packages = true
EOF
# Systemweite pip-Konfiguration für alle Benutzer
progress "Erstelle systemweite pip-Konfiguration..."
mkdir -p /etc/pip
cat > /etc/pip/pip.conf << 'EOF'
[global]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
timeout = 120
retries = 5
disable-pip-version-check = true
[install]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
user = false
EOF
# pip-Konfiguration für existierende Benutzer erstellen
progress "Konfiguriere pip für alle Benutzer..."
for user_home in "/home/"*; do
if [ -d "$user_home" ] && [ "$user_home" != "/home/lost+found" ]; then
local username=$(basename "$user_home")
if id "$username" &>/dev/null; then
mkdir -p "$user_home/.pip" 2>/dev/null || true
cat > "$user_home/.pip/pip.conf" << 'EOF'
[global]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
timeout = 60
retries = 3
[install]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
EOF
chown "$username:$username" "$user_home/.pip/pip.conf" 2>/dev/null || true
log "✅ pip konfiguriert für Benutzer: $username"
fi
fi
done
# pip selbst aktualisieren
progress "Aktualisiere pip mit Retry..."
retry_command "python3 -m pip install --break-system-packages --upgrade pip setuptools wheel" "pip Upgrade"
# pip-Version validieren
local pip_version=$(python3 -m pip --version | cut -d' ' -f2)
log "✅ pip Version: $pip_version"
log "✅ Robuste Python-Umgebung installiert"
}
install_python_packages() {
log "=== ROBUSTE PYTHON-PAKETE INSTALLATION ==="
progress "Installiere Python-Pakete mit verbesserter Strategie..."
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
# Strategie 1: Direkte Installation mit pip
progress "Versuche direkte requirements.txt Installation..."
local pip_opts="--break-system-packages --timeout 120 --retries 5 --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org"
if python3 -m pip install $pip_opts -r "$CURRENT_DIR/requirements.txt"; then
success "✅ requirements.txt erfolgreich installiert"
else
warning "⚠️ Direkte Installation fehlgeschlagen - verwende Schritt-für-Schritt Installation"
# Strategie 2: Pakete in optimierter Reihenfolge installieren
progress "Installiere Core-Abhängigkeiten zuerst..."
# Grundlegende Abhängigkeiten zuerst
local core_deps=(
"MarkupSafe==3.0.2"
"itsdangerous==2.2.0"
"click==8.1.7"
"Werkzeug==3.1.3"
"Jinja2==3.1.4"
"Flask==3.1.1"
)
for dep in "${core_deps[@]}"; do
progress "Installiere: $dep"
retry_command "python3 -m pip install $pip_opts '$dep'" "$dep Installation"
done
# Flask-Extensions
progress "Installiere Flask-Extensions..."
local flask_extensions=(
"WTForms==3.1.2"
"Flask-WTF==1.2.1"
"Flask-Login==0.6.3"
)
for ext in "${flask_extensions[@]}"; do
progress "Installiere: $ext"
retry_command "python3 -m pip install $pip_opts '$ext'" "$ext Installation"
done
# Datenbank und Sicherheit
progress "Installiere Datenbank und Sicherheits-Komponenten..."
local db_security=(
"SQLAlchemy==2.0.36"
"cryptography==44.0.0"
"bcrypt==4.2.1"
)
for comp in "${db_security[@]}"; do
progress "Installiere: $comp"
retry_command "python3 -m pip install $pip_opts '$comp'" "$comp Installation"
done
# System-Abhängigkeiten
progress "Installiere System-Abhängigkeiten..."
local system_deps=(
"requests==2.32.3"
"psutil==6.1.1"
"python-dateutil==2.9.0"
"colorlog==6.9.0"
"gunicorn==23.0.0"
)
for dep in "${system_deps[@]}"; do
progress "Installiere: $dep"
retry_command "python3 -m pip install $pip_opts '$dep'" "$dep Installation" || warning "⚠️ $dep Installation fehlgeschlagen (optional)"
done
fi
# Umfassende Validierung
progress "Validiere kritische Python-Abhängigkeiten..."
# Erstelle Validierungs-Skript
cat > /tmp/validate_python.py << 'EOF'
#!/usr/bin/env python3
import sys
import importlib
required_modules = [
('flask', 'Flask'),
('werkzeug', 'Werkzeug'),
('jinja2', 'Jinja2'),
('sqlalchemy', 'SQLAlchemy'),
('bcrypt', 'bcrypt'),
('cryptography', 'cryptography'),
('requests', 'requests'),
('psutil', 'psutil'),
('flask_login', 'Flask-Login'),
('flask_wtf', 'Flask-WTF'),
('wtforms', 'WTForms'),
('itsdangerous', 'itsdangerous'),
('markupsafe', 'MarkupSafe'),
('click', 'click')
]
failed_imports = []
successful_imports = []
for module_name, display_name in required_modules:
try:
module = importlib.import_module(module_name)
version = getattr(module, '__version__', 'Version unbekannt')
print(f"✅ {display_name}: {version}")
successful_imports.append(display_name)
except ImportError as e:
print(f"❌ {display_name}: Import fehlgeschlagen - {e}")
failed_imports.append(display_name)
except Exception as e:
print(f"⚠️ {display_name}: Unerwarteter Fehler - {e}")
failed_imports.append(display_name)
print(f"\nErgebnis: {len(successful_imports)} erfolgreich, {len(failed_imports)} fehlgeschlagen")
if failed_imports:
print("Fehlgeschlagene Module:", ", ".join(failed_imports))
sys.exit(1)
else:
print("Alle kritischen Module erfolgreich importiert!")
sys.exit(0)
EOF
if python3 /tmp/validate_python.py; then
success "✅ Alle kritischen Python-Abhängigkeiten erfolgreich validiert"
else
warning "⚠️ Einige Python-Abhängigkeiten fehlen - versuche Reparatur..."
# Repair-Versuch
retry_command "python3 -m pip install --break-system-packages --upgrade --force-reinstall Flask Werkzeug SQLAlchemy bcrypt" "Critical Package Repair"
fi
rm -f /tmp/validate_python.py
log "✅ Python-Pakete Installation abgeschlossen"
}
# =========================== ROBUSTE NODE.JS INSTALLATION ===========================
install_nodejs_npm() {
log "=== ROBUSTE NODE.JS UND NPM INSTALLATION ==="
# Alte Installationen entfernen
progress "Bereinige alte Node.js-Installationen..."
apt-get remove --purge -y nodejs npm 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
rm -rf /usr/local/bin/node /usr/local/bin/npm 2>/dev/null || true
# NodeSource Repository mit Fallback
progress "Installiere Node.js mit Fallback-Strategie..."
local nodejs_installed=false
# Strategie 1: NodeSource Repository
if curl -fsSL https://deb.nodesource.com/setup_lts.x 2>/dev/null | bash - 2>/dev/null; then
if apt-get update -y && apt_install_retry nodejs; then
nodejs_installed=true
log "✅ Node.js via NodeSource Repository installiert"
fi
fi
# Strategie 2: Snap (falls verfügbar)
if [ "$nodejs_installed" = false ] && command -v snap >/dev/null 2>&1; then
progress "Versuche Node.js Installation via Snap..."
if snap install node --classic 2>/dev/null; then
nodejs_installed=true
log "✅ Node.js via Snap installiert"
fi
fi
# Strategie 3: Debian Repository (Fallback)
if [ "$nodejs_installed" = false ]; then
progress "Verwende Debian Repository als Fallback..."
apt_install_retry nodejs npm
nodejs_installed=true
log "✅ Node.js via Debian Repository installiert"
fi
# Validierung
progress "Validiere Node.js Installation..."
if command -v node >/dev/null 2>&1; then
local node_version=$(node --version)
log "✅ Node.js Version: $node_version"
else
error "❌ Node.js nicht verfügbar nach Installation"
fi
if command -v npm >/dev/null 2>&1; then
local npm_version=$(npm --version)
log "✅ npm Version: $npm_version"
# npm optimieren
progress "Optimiere npm-Konfiguration..."
npm config set fund false 2>/dev/null || true
npm config set audit-level moderate 2>/dev/null || true
npm config set progress false 2>/dev/null || true
npm config set loglevel warn 2>/dev/null || true
else
# Versuche npm separat zu installieren
progress "Installiere npm separat..."
apt_install_retry npm
fi
log "✅ Node.js und npm erfolgreich installiert"
}
# =========================== NETZWERK-SICHERHEIT ===========================
configure_network_security() {
log "=== KONFIGURIERE ERWEITERTE NETZWERK-SICHERHEIT ==="
# IPv6 vollständig deaktivieren
progress "Deaktiviere IPv6..."
# IPv6 in GRUB deaktivieren
if [ -f /etc/default/grub ]; then
cp /etc/default/grub /etc/default/grub.backup
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="[^"]*/& ipv6.disable=1/' /etc/default/grub
sed -i 's/GRUB_CMDLINE_LINUX="[^"]*/& ipv6.disable=1/' /etc/default/grub
update-grub 2>/dev/null || true
fi
# IPv6 in sysctl deaktivieren
cat >> /etc/sysctl.conf << 'EOF'
# ===================================================================
# MYP Netzwerk-Sicherheitskonfiguration
# ===================================================================
# IPv6 vollständig deaktivieren
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
# IP-Spoofing-Schutz aktivieren
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Source-Routing deaktivieren (verhindert IP-Spoofing)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# ICMP-Redirects ignorieren (verhindert Man-in-the-Middle)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Secure ICMP-Redirects ignorieren
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# SYN-Flood-Schutz aktivieren
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# TCP-RFC-Compliance (verhindert aggressive Paketwiederholungen)
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_orphan_retries = 3
# TCP-Window-Skalierung optimieren (geringere Netzwerkauslastung)
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 5000
# Broadcast-Pings ignorieren (verhindert Smurf-Angriffe)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Bogus ICMP-Antworten ignorieren
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Paketweiterleitung verhindern (Router-Funktionalität deaktivieren)
net.ipv4.ip_forward = 0
# Martian-Pakete loggen (verdächtige Pakete)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# TCP-Timestamps deaktivieren (verhindert Fingerprinting)
net.ipv4.tcp_timestamps = 0
# TCP-SACK deaktivieren (verhindert bestimmte Angriffe)
net.ipv4.tcp_sack = 0
# TCP-Keepalive optimieren
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
# Memory-Limits für Netzwerk-Buffers
net.core.rmem_default = 262144
net.core.wmem_default = 262144
# Schutz vor Time-Wait-Assassination
net.ipv4.tcp_rfc1337 = 1
# ===================================================================
# RASPBERRY PI PERFORMANCE-OPTIMIERUNGEN FÜR WEBAPP
# ===================================================================
# Memory Management für schwache Hardware optimieren
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.vfs_cache_pressure = 50
vm.min_free_kbytes = 8192
vm.overcommit_memory = 1
# CPU Scheduler für bessere Responsivität
kernel.sched_min_granularity_ns = 10000000
kernel.sched_wakeup_granularity_ns = 15000000
kernel.sched_migration_cost_ns = 5000000
# Filesystem Performance
vm.dirty_expire_centisecs = 500
vm.dirty_writeback_centisecs = 100
# Memory Compaction für bessere Speichernutzung
vm.compact_memory = 1
# OOM Killer weniger aggressiv
vm.oom_kill_allocating_task = 0
vm.panic_on_oom = 0
# Kernel Preemption für bessere Interaktivität
kernel.sched_rt_runtime_us = 950000
kernel.sched_rt_period_us = 1000000
# I/O Scheduler Optimierungen für SD-Karte
# (wird später per udev-Regel angewendet)
EOF
# Sysctl-Einstellungen sofort anwenden
sysctl -p || warning "Einige sysctl-Einstellungen konnten nicht angewendet werden"
# IPv6 in Netzwerk-Interfaces deaktivieren
progress "Deaktiviere IPv6 in Netzwerk-Interfaces..."
# Für systemd-networkd
if systemctl is-enabled systemd-networkd 2>/dev/null; then
mkdir -p /etc/systemd/network
cat > /etc/systemd/network/99-disable-ipv6.network << 'EOF'
[Match]
Name=*
[Network]
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
systemctl restart systemd-networkd 2>/dev/null || true
fi
# Für NetworkManager
if systemctl is-enabled NetworkManager 2>/dev/null; then
cat > /etc/NetworkManager/conf.d/99-disable-ipv6.conf << 'EOF'
[main]
plugins=keyfile
[keyfile]
unmanaged-devices=none
[connection]
ipv6.method=ignore
EOF
systemctl restart NetworkManager 2>/dev/null || true
fi
# IPv6 in /etc/hosts auskommentieren
sed -i 's/^::1/#::1/' /etc/hosts 2>/dev/null || true
log "✅ Erweiterte Netzwerk-Sicherheit konfiguriert:"
log " 🚫 IPv6 vollständig deaktiviert"
log " 🛡️ IP-Spoofing-Schutz aktiviert"
log " 🔒 SYN-Flood-Schutz aktiviert"
log " 📝 Verdächtige Pakete werden geloggt"
log " 🚫 Paketweiterleitung deaktiviert"
log " ⚡ TCP-Performance optimiert"
log " 🔐 RFC-Compliance für TCP aktiviert"
}
# =========================== DESKTOP-ENVIRONMENT ENTFERNUNG ===========================
remove_desktop_environments() {
log "=== ENTFERNE DESKTOP ENVIRONMENTS FÜR KIOSK-MODUS ==="
progress "Stoppe alle Desktop-Services..."
local desktop_services=("lightdm" "gdm3" "sddm" "xdm" "nodm")
for service in "${desktop_services[@]}"; do
systemctl stop "$service" 2>/dev/null || true
systemctl disable "$service" 2>/dev/null || true
done
progress "Entferne Desktop-Pakete vollständig..."
# Raspberry Pi OS Desktop-Pakete
apt-get remove --purge -y \
raspberrypi-ui-mods \
pi-package \
desktop-base \
lxde* \
xfce4* \
gnome* \
kde* \
mate* \
cinnamon* \
openbox \
pcmanfm \
file-manager* \
task-lxde-desktop \
task-xfce-desktop \
task-gnome-desktop \
task-kde-desktop \
2>/dev/null || true
# Display Manager entfernen
apt-get remove --purge -y \
lightdm* \
gdm3* \
sddm* \
xdm* \
nodm* \
2>/dev/null || true
# Unnötige Anwendungen entfernen
apt-get remove --purge -y \
libreoffice* \
thunderbird* \
firefox* \
vlc* \
gimp* \
scratch* \
minecraft-pi \
sonic-pi \
2>/dev/null || true
# Aufräumen
apt-get autoremove --purge -y
apt-get autoclean
log "✅ Desktop Environments vollständig entfernt"
}
# =========================== MINIMALE X11-UMGEBUNG ===========================
install_minimal_x11() {
log "=== INSTALLIERE MINIMALE X11-UMGEBUNG FÜR KIOSK ==="
progress "Installiere minimale X11-Pakete..."
apt-get install -y \
xserver-xorg-core \
xserver-xorg-input-all \
xserver-xorg-video-fbdev \
xserver-xorg-video-vesa \
xinit \
x11-xserver-utils \
xdotool \
unclutter \
openbox \
|| error "X11 Installation fehlgeschlagen"
# Browser-Installation mit Fallback-Mechanismus
progress "Installiere Browser für Kiosk-Modus..."
local browser_installed=false
# Versuche Chromium zu installieren
if apt-get install -y chromium 2>/dev/null; then
log "✅ Chromium erfolgreich installiert"
browser_installed=true
elif apt-get install -y chromium-browser 2>/dev/null; then
log "✅ Chromium-Browser erfolgreich installiert"
browser_installed=true
elif apt-get install -y firefox-esr 2>/dev/null; then
warning "⚠️ Chromium nicht verfügbar - Firefox ESR als Fallback installiert"
browser_installed=true
fi
if [ "$browser_installed" = false ]; then
error "❌ Kein Browser verfügbar (chromium, chromium-browser, firefox-esr)"
fi
log "✅ Minimale X11-Umgebung installiert"
}
# =========================== KIOSK-BENUTZER MANAGEMENT ===========================
create_kiosk_user() {
log "=== KIOSK-BENUTZER SETUP ==="
if ! id "$KIOSK_USER" &>/dev/null; then
progress "Erstelle Kiosk-Benutzer: $KIOSK_USER"
useradd -m -s /bin/bash "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen"
# Gruppen hinzufügen
usermod -aG audio,video,input,dialout,plugdev,users "$KIOSK_USER" 2>/dev/null || true
# pip-Konfiguration für Kiosk-Benutzer
local kiosk_home="/home/$KIOSK_USER"
mkdir -p "$kiosk_home/.pip" 2>/dev/null || true
cat > "$kiosk_home/.pip/pip.conf" << 'EOF'
[global]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
timeout = 60
retries = 3
[install]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
EOF
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.pip/pip.conf" 2>/dev/null || true
else
info "Kiosk-Benutzer $KIOSK_USER existiert bereits"
fi
# Passwort entfernen für automatischen Login
passwd -d "$KIOSK_USER" || warning "Konnte Passwort nicht entfernen"
log "✅ Kiosk-Benutzer konfiguriert: $KIOSK_USER"
}
configure_autologin() {
log "=== KONFIGURIERE AUTOLOGIN FÜR KIOSK-BENUTZER ==="
# Getty-Service für automatischen Login konfigurieren
progress "Konfiguriere automatischen Login auf tty1..."
local getty_override_dir="/etc/systemd/system/getty@tty1.service.d"
mkdir -p "$getty_override_dir"
cat > "$getty_override_dir/override.conf" << EOF
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin $KIOSK_USER --noclear %I \$TERM
EOF
# Systemd-Konfiguration neu laden
systemctl daemon-reload
systemctl enable getty@tty1.service
log "✅ Autologin für $KIOSK_USER konfiguriert"
}
configure_kiosk_autostart() {
log "=== KONFIGURIERE AUTOMATISCHEN KIOSK-START ==="
# Erstelle .bashrc für automatischen X-Server und Browser-Start
progress "Konfiguriere automatischen Kiosk-Start für $KIOSK_USER..."
local kiosk_home="/home/$KIOSK_USER"
# .bashrc für automatischen Start erstellen
cat > "$kiosk_home/.bashrc" << 'EOF'
# Automatischer Kiosk-Start beim Login
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
echo "Starte Kiosk-Modus..."
# X-Server im Hintergrund starten
startx /home/kiosk/.xinitrc -- :0 vt1 &
# Warte bis X-Server bereit ist
sleep 5
# Setze DISPLAY-Variable
export DISPLAY=:0
# Warte auf HTTPS-Backend
echo "Warte auf HTTPS-Backend..."
for i in {1..60}; do
if curl -k -s https://localhost:443 >/dev/null 2>&1; then
echo "HTTPS-Backend erreichbar"
break
fi
echo "Warte... ($i/60)"
sleep 2
done
# Bildschirmschoner deaktivieren
xset s off
xset s noblank
xset -dpms
# Mauszeiger verstecken
unclutter -idle 0.1 -root -noevents &
# Browser im Kiosk-Modus starten
if command -v chromium >/dev/null 2>&1; then
BROWSER="chromium"
elif command -v chromium-browser >/dev/null 2>&1; then
BROWSER="chromium-browser"
else
BROWSER="firefox-esr"
fi
echo "Starte $BROWSER im Kiosk-Modus..."
if [[ "$BROWSER" == "chromium"* ]]; then
exec $BROWSER \
--kiosk \
--no-sandbox \
--disable-infobars \
--disable-session-crashed-bubble \
--disable-restore-session-state \
--disable-features=TranslateUI \
--disable-extensions \
--disable-plugins \
--disable-popup-blocking \
--disable-prompt-on-repost \
--disable-sync \
--disable-translate \
--noerrdialogs \
--no-first-run \
--no-default-browser-check \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--start-maximized \
--user-data-dir=/home/kiosk/.chromium-kiosk \
--disable-background-mode \
--force-device-scale-factor=1.0 \
--disable-pinch \
--overscroll-history-navigation=0 \
--disable-dev-shm-usage \
--memory-pressure-off \
--max_old_space_size=512 \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--disable-features=VizDisplayCompositor \
--enable-features=OverlayScrollbar \
--hide-scrollbars \
--ignore-certificate-errors \
--ignore-ssl-errors \
--ignore-certificate-errors-spki-list \
--disable-web-security \
--allow-running-insecure-content \
--unsafely-treat-insecure-origin-as-secure=https://localhost:443 \
https://localhost:443
else
exec firefox-esr \
--kiosk \
https://localhost:443
fi
fi
EOF
# .xinitrc für X-Server-Konfiguration erstellen
cat > "$kiosk_home/.xinitrc" << 'EOF'
#!/bin/bash
# Minimale X-Session für Kiosk-Modus
exec openbox-session
EOF
# Berechtigungen setzen
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.xinitrc"
chmod +x "$kiosk_home/.xinitrc"
# Erstelle Kiosk-Verzeichnisse
mkdir -p "$kiosk_home/.chromium-kiosk"
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.chromium-kiosk"
log "✅ Automatischer Kiosk-Start konfiguriert"
info "Der Kiosk-Modus startet automatisch beim Login des $KIOSK_USER"
}
# =========================== ROBUSTE SSL-ZERTIFIKATE INSTALLATION ===========================
install_ssl_certificates() {
log "=== ROBUSTE SSL-ZERTIFIKATE KONFIGURATION ==="
progress "Installiere SSL-Grundkomponenten..."
apt_install_retry ca-certificates openssl
progress "Aktualisiere CA-Zertifikate..."
retry_command "update-ca-certificates" "CA-Zertifikate Update"
# SSL-Verzeichnisse sicherstellen
mkdir -p /usr/local/share/ca-certificates/myp
# Mercedes Corporate Zertifikate (robuster)
if [ -d "$CURRENT_DIR/certs/mercedes" ] && [ "$(ls -A $CURRENT_DIR/certs/mercedes 2>/dev/null)" ]; then
progress "Installiere Mercedes Corporate Zertifikate (robust)..."
local cert_count=0
local installed_count=0
find "$CURRENT_DIR/certs/mercedes" -type f \( -name "*.crt" -o -name "*.pem" -o -name "*.cer" \) | while read cert_file; do
((cert_count++))
local cert_basename=$(basename "$cert_file")
local cert_name="${cert_basename%.*}"
local target_file="/usr/local/share/ca-certificates/myp/${cert_name}.crt"
progress "Verarbeite Mercedes-Zertifikat: $cert_basename"
# Robuste Zertifikat-Validierung und Installation
if openssl x509 -in "$cert_file" -text -noout >/dev/null 2>&1; then
# PEM Format
if cp "$cert_file" "$target_file" 2>/dev/null; then
log "✅ PEM-Zertifikat installiert: ${cert_name}.crt"
((installed_count++))
fi
elif openssl x509 -in "$cert_file" -inform DER -text -noout >/dev/null 2>&1; then
# DER Format - zu PEM konvertieren
if openssl x509 -in "$cert_file" -inform DER -out "$target_file" -outform PEM 2>/dev/null; then
log "✅ DER-Zertifikat konvertiert und installiert: ${cert_name}.crt"
((installed_count++))
fi
else
warning "⚠️ Ungültiges Zertifikat übersprungen: $cert_file"
fi
done
if [ $installed_count -gt 0 ]; then
progress "Lade CA-Zertifikate nach Mercedes-Import neu..."
retry_command "update-ca-certificates" "Mercedes Zertifikate Update"
log "$installed_count von $cert_count Mercedes-Zertifikaten erfolgreich installiert"
fi
fi
# SSL-Umgebungsvariablen systemweit setzen
progress "Konfiguriere SSL-Umgebungsvariablen..."
cat >> /etc/environment << 'EOF'
# SSL Certificate Configuration für MYP
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
EOF
# SSL-Umgebungsvariablen für aktuelle Session
export SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt"
export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
export CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
# Validiere SSL-Setup
progress "Validiere SSL-Konfiguration..."
if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then
local cert_count=$(grep -c "BEGIN CERTIFICATE" /etc/ssl/certs/ca-certificates.crt 2>/dev/null || echo "0")
log "✅ SSL-Zertifikate verfügbar: $cert_count CA-Zertifikate"
else
warning "⚠️ CA-Zertifikate-Datei nicht gefunden"
fi
log "✅ SSL-Zertifikate robust konfiguriert"
}
# =========================== ROBUSTES ANWENDUNGS-DEPLOYMENT ===========================
deploy_application() {
log "=== ROBUSTES ANWENDUNGS-DEPLOYMENT ==="
progress "Erstelle sicheres Zielverzeichnis: $APP_DIR"
mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen"
# Validiere Source-Verzeichnis
progress "Validiere Source-Dateien..."
if [ ! -f "$CURRENT_DIR/app.py" ]; then
error "Kritische Datei nicht gefunden: $CURRENT_DIR/app.py"
fi
if [ ! -f "$CURRENT_DIR/requirements.txt" ]; then
error "Kritische Datei nicht gefunden: $CURRENT_DIR/requirements.txt"
fi
progress "Kopiere Anwendungsdateien (robust)..."
# Kritische Dateien zuerst (mit Validierung)
local critical_files=(
"app.py"
"models.py"
"requirements.txt"
)
for file in "${critical_files[@]}"; do
if [ -f "$CURRENT_DIR/$file" ]; then
progress "Kopiere kritische Datei: $file"
if cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null; then
success "$file erfolgreich kopiert"
else
error "❌ Fehler beim Kopieren der kritischen Datei: $file"
fi
else
error "❌ Kritische Datei fehlt: $file"
fi
done
# Verzeichnisse mit robuster Behandlung
local directories=(
"blueprints"
"config"
"database"
"static"
"templates"
"uploads"
"utils"
"logs"
"certs"
)
for dir in "${directories[@]}"; do
if [ -d "$CURRENT_DIR/$dir" ]; then
progress "Kopiere Verzeichnis: $dir"
if cp -r "$CURRENT_DIR/$dir" "$APP_DIR/" 2>/dev/null; then
success "$dir erfolgreich kopiert"
else
warning "⚠️ Fehler beim Kopieren von $dir (möglicherweise nicht kritisch)"
fi
else
info "Verzeichnis nicht vorhanden: $dir"
fi
done
# Optionale Dateien
local optional_files=(
"package.json"
"package-lock.json"
"tailwind.config.js"
"postcss.config.js"
"README.md"
".gitignore"
)
for file in "${optional_files[@]}"; do
if [ -f "$CURRENT_DIR/$file" ]; then
progress "Kopiere optionale Datei: $file"
cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null || warning "⚠️ Kopieren von $file fehlgeschlagen"
fi
done
# Erstelle alle notwendigen Verzeichnisse mit korrekter Struktur
progress "Erstelle Verzeichnisstruktur..."
local required_dirs=(
"database/backups"
"logs/app"
"logs/auth"
"logs/errors"
"logs/system"
"uploads/temp"
"uploads/assets"
"uploads/avatars"
"uploads/backups"
"uploads/jobs"
"certs/localhost"
"instance"
"instance/ssl"
)
for dir in "${required_dirs[@]}"; do
mkdir -p "$APP_DIR/$dir" 2>/dev/null || warning "⚠️ Verzeichnis $dir konnte nicht erstellt werden"
done
# Sichere Berechtigungen setzen (robuster)
progress "Setze sichere Berechtigungen..."
# Basis-Berechtigungen
chown -R root:root "$APP_DIR" 2>/dev/null || warning "⚠️ Ownership konnte nicht gesetzt werden"
chmod 755 "$APP_DIR" 2>/dev/null || warning "⚠️ Verzeichnis-Permissions konnten nicht gesetzt werden"
# Ausführbare Dateien
if [ -f "$APP_DIR/app.py" ]; then
chmod +x "$APP_DIR/app.py" 2>/dev/null || warning "⚠️ app.py Ausführberechtigung konnte nicht gesetzt werden"
fi
# Sensitive Verzeichnisse
chmod 750 "$APP_DIR/database" 2>/dev/null || true
chmod 750 "$APP_DIR/logs" 2>/dev/null || true
chmod 750 "$APP_DIR/certs" 2>/dev/null || true
chmod 750 "$APP_DIR/instance" 2>/dev/null || true
# Upload-Verzeichnisse
chmod 755 "$APP_DIR/uploads" 2>/dev/null || true
chmod 755 "$APP_DIR/static" 2>/dev/null || true
# Python-Umgebung robust konfigurieren
progress "Konfiguriere robuste Python-Umgebung..."
# Ermittle Python site-packages Verzeichnis (robust)
local python_site_packages=""
for possible_path in \
"$(python3 -c "import site; print(site.getsitepackages()[0])" 2>/dev/null)" \
"/usr/local/lib/python3/dist-packages" \
"/usr/lib/python3/dist-packages" \
"/usr/local/lib/python$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)/dist-packages"; do
if [ -d "$possible_path" ]; then
python_site_packages="$possible_path"
break
fi
done
if [ -n "$python_site_packages" ]; then
echo "$APP_DIR" > "$python_site_packages/myp-app.pth" 2>/dev/null || warning "⚠️ Python-Pfad konnte nicht konfiguriert werden"
log "✅ Python-Pfad konfiguriert: $python_site_packages/myp-app.pth"
else
warning "⚠️ Python site-packages Verzeichnis nicht gefunden"
fi
# Systemweite Umgebungsvariablen robust setzen
progress "Konfiguriere Umgebungsvariablen..."
cat >> /etc/environment << EOF
# MYP Application Environment
MYP_APP_DIR=$APP_DIR
PYTHONPATH=$APP_DIR:\${PYTHONPATH:-}
FLASK_APP=$APP_DIR/app.py
FLASK_ENV=production
EOF
# Bash-Profile für alle User aktualisieren (robust)
progress "Aktualisiere Bash-Profile..."
local profile_updated=0
for user_home in "/root" "/home/"*; do
if [ -d "$user_home" ] && [ "$user_home" != "/home/lost+found" ] && [ -w "$user_home" ]; then
if ! grep -q "MYP Application Environment" "$user_home/.bashrc" 2>/dev/null; then
cat >> "$user_home/.bashrc" << 'EOF'
# MYP Application Environment
if [ -d "/opt/myp" ]; then
export MYP_APP_DIR="/opt/myp"
export FLASK_APP="/opt/myp/app.py"
export FLASK_ENV="production"
if [ -z "${PYTHONPATH:-}" ]; then
export PYTHONPATH="/opt/myp"
else
export PYTHONPATH="/opt/myp:$PYTHONPATH"
fi
fi
EOF
((profile_updated++))
log "✅ Bash-Profile aktualisiert: $user_home/.bashrc"
fi
fi
done
# Validiere Deployment
progress "Validiere Application Deployment..."
local validation_errors=0
# Prüfe kritische Dateien
for file in "app.py" "models.py" "requirements.txt"; do
if [ ! -f "$APP_DIR/$file" ]; then
warning "❌ Kritische Datei fehlt: $file"
((validation_errors++))
fi
done
# Prüfe wichtige Verzeichnisse
for dir in "static" "templates" "blueprints"; do
if [ ! -d "$APP_DIR/$dir" ]; then
warning "❌ Wichtiges Verzeichnis fehlt: $dir"
((validation_errors++))
fi
done
if [ $validation_errors -eq 0 ]; then
success "✅ Application Deployment vollständig validiert"
else
warning "⚠️ $validation_errors Probleme beim Deployment gefunden"
fi
log "✅ Robustes Anwendungs-Deployment abgeschlossen"
log " 📁 App-Verzeichnis: $APP_DIR"
log " 🐍 Python-Pfad konfiguriert"
log " 🔧 $profile_updated Bash-Profile aktualisiert"
log " 🛡️ Sichere Berechtigungen gesetzt"
}
install_npm_dependencies() {
log "=== NPM-ABHÄNGIGKEITEN INSTALLATION ==="
if [ -f "$APP_DIR/package.json" ]; then
progress "Installiere npm-Abhängigkeiten..."
cd "$APP_DIR"
# npm install mit verschiedenen Fallback-Strategien
if npm install --no-optional --no-audit --no-fund 2>/dev/null; then
log "✅ npm install erfolgreich (Standard)"
elif npm install --legacy-peer-deps --no-optional 2>/dev/null; then
log "✅ npm install erfolgreich (Legacy-Modus)"
elif npm install --force 2>/dev/null; then
log "✅ npm install erfolgreich (Force-Modus)"
else
warning "⚠️ npm install fehlgeschlagen - überspringe"
fi
cd "$CURRENT_DIR"
else
info "Keine package.json gefunden - überspringe npm-Installation"
fi
log "✅ NPM-Abhängigkeiten verarbeitet"
}
# =========================== SSL-ZERTIFIKAT GENERIERUNG ===========================
generate_ssl_certificate() {
log "=== SSL-ZERTIFIKAT GENERIERUNG ==="
progress "Generiere selbstsigniertes SSL-Zertifikat für localhost..."
local cert_dir="$APP_DIR/certs/localhost"
mkdir -p "$cert_dir"
# Generiere privaten Schlüssel
openssl genrsa -out "$cert_dir/localhost.key" 2048 || error "Fehler beim Generieren des privaten Schlüssels"
# Generiere Zertifikat
openssl req -new -x509 -key "$cert_dir/localhost.key" -out "$cert_dir/localhost.crt" -days 365 \
-subj "/C=DE/ST=Baden-Wuerttemberg/L=Stuttgart/O=Mercedes-Benz/OU=IT/CN=localhost" \
|| error "Fehler beim Generieren des SSL-Zertifikats"
# Berechtigungen setzen
chmod 600 "$cert_dir/localhost.key"
chmod 644 "$cert_dir/localhost.crt"
log "✅ SSL-Zertifikat erfolgreich generiert"
}
# =========================== ROBUSTE SYSTEMD-SERVICES INSTALLATION ===========================
install_systemd_services() {
log "=== ROBUSTE SYSTEMD-SERVICES INSTALLATION ==="
# Validiere systemd-Verzeichnis
if [ ! -d "$SYSTEMD_DIR" ]; then
error "systemd-Verzeichnis nicht gefunden: $SYSTEMD_DIR"
fi
progress "Validiere und kopiere Service-Dateien..."
# Definiere Service-Dateien mit Priorität
local essential_services=(
"$HTTPS_SERVICE_NAME.service"
)
local optional_services=(
"$KIOSK_SERVICE_NAME.service"
"$WATCHDOG_SERVICE_NAME.service"
"$WATCHDOG_PYTHON_SERVICE_NAME.service"
"$FIREWALL_SERVICE_NAME.service"
)
local installed_services=0
local essential_errors=0
# Essenzielle Services zuerst
for service_file in "${essential_services[@]}"; do
if [ -f "$SYSTEMD_DIR/$service_file" ]; then
progress "Kopiere essenziellen Service: $service_file"
if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then
success "$service_file erfolgreich installiert"
((installed_services++))
else
error "❌ Fehler beim Kopieren des essenziellen Service: $service_file"
((essential_errors++))
fi
else
error "❌ Essenzieller Service nicht gefunden: $service_file"
((essential_errors++))
fi
done
# Optionale Services
for service_file in "${optional_services[@]}"; do
if [ -f "$SYSTEMD_DIR/$service_file" ]; then
progress "Kopiere optionalen Service: $service_file"
if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then
success "$service_file erfolgreich installiert"
((installed_services++))
else
warning "⚠️ Fehler beim Kopieren des optionalen Service: $service_file"
fi
else
info "Optionaler Service nicht gefunden: $service_file"
fi
done
# Prüfe auf kritische Fehler
if [ $essential_errors -gt 0 ]; then
error "$essential_errors essenzielle Services konnten nicht installiert werden!"
fi
# Validiere kopierte Service-Dateien
progress "Validiere Service-Dateien..."
for service_file in "${essential_services[@]}" "${optional_services[@]}"; do
if [ -f "$SYSTEM_SYSTEMD_DIR/$service_file" ]; then
# Syntaxprüfung für systemd-Services
if systemd-analyze verify "$SYSTEM_SYSTEMD_DIR/$service_file" 2>/dev/null; then
success "$service_file Syntax-Validierung erfolgreich"
else
warning "⚠️ $service_file hat möglicherweise Syntax-Probleme"
fi
fi
done
# Systemd-Konfiguration neu laden
progress "Lade systemd-Konfiguration neu..."
retry_command "systemctl daemon-reload" "systemd daemon-reload"
log "✅ Systemd-Services installiert: $installed_services Services"
}
enable_and_start_services() {
log "=== ROBUSTE SERVICES AKTIVIERUNG UND START ==="
# Service-Status tracking
local successful_services=0
local failed_services=0
# HTTPS-Service (kritisch)
progress "Aktiviere und starte HTTPS-Service (kritisch)..."
if systemctl enable "$HTTPS_SERVICE_NAME" 2>/dev/null; then
success "✅ HTTPS-Service erfolgreich aktiviert"
if systemctl start "$HTTPS_SERVICE_NAME" 2>/dev/null; then
success "✅ HTTPS-Service erfolgreich gestartet"
# Warte und prüfe Status gründlich
local startup_timeout=15
local check_interval=2
local elapsed=0
while [ $elapsed -lt $startup_timeout ]; do
if systemctl is-active --quiet "$HTTPS_SERVICE_NAME"; then
success "✅ HTTPS-Service läuft stabil nach ${elapsed}s"
((successful_services++))
break
fi
sleep $check_interval
elapsed=$((elapsed + check_interval))
progress "Warte auf HTTPS-Service Startup... (${elapsed}/${startup_timeout}s)"
done
if [ $elapsed -ge $startup_timeout ]; then
error "❌ HTTPS-Service Timeout nach ${startup_timeout}s - Service nicht verfügbar"
# Debugging-Informationen
info "HTTPS-Service Status-Debug:"
systemctl status "$HTTPS_SERVICE_NAME" --no-pager -l || true
journalctl -u "$HTTPS_SERVICE_NAME" --no-pager -n 10 || true
((failed_services++))
fi
else
error "❌ HTTPS-Service konnte nicht gestartet werden"
((failed_services++))
fi
else
error "❌ HTTPS-Service konnte nicht aktiviert werden"
((failed_services++))
fi
# Kiosk-Service (für Produktionsinstallation)
if [ -f "$SYSTEM_SYSTEMD_DIR/$KIOSK_SERVICE_NAME.service" ]; then
progress "Aktiviere Kiosk-Service (startet beim nächsten Boot)..."
if systemctl enable "$KIOSK_SERVICE_NAME" 2>/dev/null; then
success "✅ Kiosk-Service erfolgreich aktiviert"
((successful_services++))
else
warning "⚠️ Kiosk-Service konnte nicht aktiviert werden"
((failed_services++))
fi
fi
# Watchdog-Service (optional)
if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_SERVICE_NAME.service" ]; then
progress "Aktiviere und starte Watchdog-Service..."
if systemctl enable "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then
if systemctl start "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then
success "✅ Watchdog-Service erfolgreich aktiviert und gestartet"
((successful_services++))
else
warning "⚠️ Watchdog-Service aktiviert, aber Start fehlgeschlagen"
fi
else
warning "⚠️ Watchdog-Service konnte nicht aktiviert werden"
fi
fi
# Python Watchdog-Service (optional)
if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_PYTHON_SERVICE_NAME.service" ]; then
progress "Aktiviere Python Watchdog-Service..."
if systemctl enable "$WATCHDOG_PYTHON_SERVICE_NAME" 2>/dev/null; then
success "✅ Python Watchdog-Service erfolgreich aktiviert"
((successful_services++))
else
warning "⚠️ Python Watchdog-Service konnte nicht aktiviert werden"
fi
fi
# Firewall-Service (optional)
if [ -f "$SYSTEM_SYSTEMD_DIR/$FIREWALL_SERVICE_NAME.service" ]; then
progress "Aktiviere Firewall-Service..."
if systemctl enable "$FIREWALL_SERVICE_NAME" 2>/dev/null; then
success "✅ Firewall-Service erfolgreich aktiviert"
((successful_services++))
else
warning "⚠️ Firewall-Service konnte nicht aktiviert werden"
fi
fi
# Zusammenfassung
log "📊 Service-Aktivierung Zusammenfassung:"
log " ✅ Erfolgreich: $successful_services Services"
log " ❌ Fehlgeschlagen: $failed_services Services"
if [ $failed_services -eq 0 ]; then
success "✅ Alle verfügbaren Services erfolgreich konfiguriert"
elif [ $successful_services -gt 0 ]; then
warning "⚠️ $failed_services Services fehlgeschlagen, aber $successful_services Services funktionieren"
info "→ System ist grundsätzlich funktionsfähig"
else
error "❌ Alle Services fehlgeschlagen - System möglicherweise nicht funktionsfähig"
fi
}
# =========================== ROBUSTE SYSTEM-TESTS ===========================
test_application() {
log "=== UMFASSENDE SYSTEM-TESTS ==="
local test_errors=0
local test_warnings=0
# Test 1: Service-Status prüfen
progress "Teste Service-Status..."
if systemctl is-active --quiet "$HTTPS_SERVICE_NAME"; then
success "✅ HTTPS-Service ist aktiv"
else
warning "⚠️ HTTPS-Service ist nicht aktiv"
((test_warnings++))
# Debug-Informationen
info "Service-Status Debug:"
systemctl status "$HTTPS_SERVICE_NAME" --no-pager -l || true
fi
# Test 2: Port-Verfügbarkeit
progress "Teste Port-Verfügbarkeit..."
if ss -tlnp | grep -q ":443 "; then
success "✅ Port 443 ist geöffnet"
else
warning "⚠️ Port 443 ist nicht geöffnet"
((test_warnings++))
fi
# Test 3: HTTPS-Verbindung (robust mit mehreren Methoden)
progress "Teste HTTPS-Verbindung (robust)..."
local max_attempts=20
local attempt=1
local connection_successful=false
while [ $attempt -le $max_attempts ]; do
# Methode 1: curl mit verschiedenen Optionen
if curl -k -s --connect-timeout 3 --max-time 8 "$HTTPS_URL" >/dev/null 2>&1; then
connection_successful=true
break
fi
# Methode 2: wget als Fallback
if command -v wget >/dev/null 2>&1; then
if wget -q --no-check-certificate --timeout=3 --tries=1 "$HTTPS_URL" -O /dev/null 2>/dev/null; then
connection_successful=true
break
fi
fi
# Methode 3: openssl s_client als direkter Test
if echo "GET / HTTP/1.0" | openssl s_client -connect localhost:443 -quiet 2>/dev/null | grep -q "HTTP"; then
connection_successful=true
break
fi
progress "Warte auf HTTPS-Backend... ($attempt/$max_attempts)"
sleep 3
((attempt++))
done
if [ "$connection_successful" = true ]; then
success "✅ HTTPS-Backend erreichbar unter $HTTPS_URL"
# Erweiterte Verbindungstests
progress "Führe erweiterte HTTPS-Tests durch..."
# Test Antwortzeit
local response_time=$(curl -k -s -w "%{time_total}" -o /dev/null "$HTTPS_URL" 2>/dev/null || echo "timeout")
if [ "$response_time" != "timeout" ]; then
info "🕐 HTTPS Antwortzeit: ${response_time}s"
# Bewerte Antwortzeit
if [ "$(echo "$response_time < 2.0" | bc 2>/dev/null || echo "0")" -eq 1 ]; then
success "✅ Gute Antwortzeit"
elif [ "$(echo "$response_time < 5.0" | bc 2>/dev/null || echo "0")" -eq 1 ]; then
info " Akzeptable Antwortzeit"
else
warning "⚠️ Langsame Antwortzeit"
((test_warnings++))
fi
fi
# Test HTTP-Status
local http_status=$(curl -k -s -o /dev/null -w "%{http_code}" "$HTTPS_URL" 2>/dev/null || echo "000")
if [ "$http_status" = "200" ]; then
success "✅ HTTP Status 200 OK"
else
info " HTTP Status: $http_status (möglicherweise Redirect oder Login-Seite)"
fi
else
error "❌ HTTPS-Backend nicht erreichbar nach $max_attempts Versuchen"
((test_errors++))
# Debugging-Informationen
info "HTTPS-Debug Informationen:"
netstat -tlnp | grep ":443" || info "Port 443 nicht gefunden"
ss -tlnp | grep ":443" || info "Port 443 nicht in ss gefunden"
fi
# Test 4: SSL-Zertifikat (erweitert)
progress "Teste SSL-Zertifikat (erweitert)..."
# Methode 1: openssl s_client
if echo | openssl s_client -connect localhost:443 -servername localhost 2>/dev/null | openssl x509 -noout -text >/dev/null 2>&1; then
success "✅ SSL-Zertifikat ist gültig"
# Zertifikat-Details extrahieren
local cert_info=$(echo | openssl s_client -connect localhost:443 -servername localhost 2>/dev/null | openssl x509 -noout -subject -dates 2>/dev/null || echo "Nicht verfügbar")
info "📜 Zertifikat-Info: $cert_info"
else
warning "⚠️ SSL-Zertifikat-Test fehlgeschlagen"
((test_warnings++))
# Alternative: Teste ob Zertifikat-Dateien existieren
if [ -f "$APP_DIR/certs/localhost/localhost.crt" ] && [ -f "$APP_DIR/certs/localhost/localhost.key" ]; then
info "📁 SSL-Zertifikat-Dateien sind vorhanden"
# Teste Zertifikat-Datei direkt
if openssl x509 -in "$APP_DIR/certs/localhost/localhost.crt" -noout -text >/dev/null 2>&1; then
success "✅ SSL-Zertifikat-Datei ist gültig"
else
warning "⚠️ SSL-Zertifikat-Datei ist ungültig"
((test_warnings++))
fi
fi
fi
# Test 5: Python-Anwendung Import-Test
progress "Teste Python-Anwendung Import..."
cd "$APP_DIR" 2>/dev/null || true
# Setze Test-Umgebung
export FLASK_ENV=testing
export MYP_TESTING=1
export PYTHONPATH="$APP_DIR:${PYTHONPATH:-}"
if timeout 15 python3 -c "
import sys
import os
sys.path.insert(0, '$APP_DIR')
os.chdir('$APP_DIR')
try:
import app
print('✅ Flask-App Import erfolgreich')
# Test ob Flask-App-Objekt verfügbar
if hasattr(app, 'app'):
print('✅ Flask-App-Objekt verfügbar')
else:
print('⚠️ Flask-App-Objekt nicht gefunden')
except Exception as e:
print(f'⚠️ App-Import-Problem: {e}')
exit(1)
" 2>&1; then
success "✅ Python-Anwendung kann erfolgreich importiert werden"
else
warning "⚠️ Python-Anwendung Import-Probleme (möglicherweise nicht kritisch)"
((test_warnings++))
fi
cd "$CURRENT_DIR" 2>/dev/null || true
# Test 6: Verzeichnisstruktur-Validierung
progress "Validiere Verzeichnisstruktur..."
local structure_ok=true
local required_files=("$APP_DIR/app.py" "$APP_DIR/models.py" "$APP_DIR/requirements.txt")
local required_dirs=("$APP_DIR/static" "$APP_DIR/templates" "$APP_DIR/blueprints")
for file in "${required_files[@]}"; do
if [ ! -f "$file" ]; then
warning "❌ Wichtige Datei fehlt: $file"
structure_ok=false
((test_warnings++))
fi
done
for dir in "${required_dirs[@]}"; do
if [ ! -d "$dir" ]; then
warning "❌ Wichtiges Verzeichnis fehlt: $dir"
structure_ok=false
((test_warnings++))
fi
done
if [ "$structure_ok" = true ]; then
success "✅ Verzeichnisstruktur vollständig"
fi
# Zusammenfassung der Tests
log "📊 System-Test Zusammenfassung:"
log " ❌ Fehler: $test_errors"
log " ⚠️ Warnungen: $test_warnings"
if [ $test_errors -eq 0 ] && [ $test_warnings -eq 0 ]; then
success "✅ Alle System-Tests erfolgreich - System vollständig funktionsfähig"
return 0
elif [ $test_errors -eq 0 ]; then
warning "⚠️ System-Tests mit $test_warnings Warnungen abgeschlossen - System grundsätzlich funktionsfähig"
return 0
else
error "❌ System-Tests mit $test_errors Fehlern fehlgeschlagen - System möglicherweise nicht funktionsfähig"
return 1
fi
}
# =========================== AUFRÄUMEN ===========================
cleanup_old_files() {
log "=== AUFRÄUMEN ALTE DATEIEN ==="
progress "Entferne alte Shell-Skripte..."
# Entferne alte Skripte (falls vorhanden)
local old_scripts=("combined.sh" "installer.sh")
for script in "${old_scripts[@]}"; do
if [ -f "$CURRENT_DIR/$script" ]; then
progress "Entferne: $script"
rm -f "$CURRENT_DIR/$script" || warning "Fehler beim Entfernen von $script"
fi
done
log "✅ Aufräumen abgeschlossen"
}
# =========================== HAUPTMENÜ ===========================
show_menu() {
clear
echo -e "${CYAN}=================================================================${NC}"
echo -e "${CYAN} $APP_NAME - Setup-Skript v$APP_VERSION${NC}"
echo -e "${CYAN}=================================================================${NC}"
echo ""
echo -e "${YELLOW}Bitte wählen Sie eine Option:${NC}"
echo ""
echo -e "${GREEN}1)${NC} Abhängigkeiten installieren und System für manuelles Testen vorbereiten"
echo -e " ${BLUE}→ Python, Node.js, SSL-Zertifikate, Anwendung deployed, minimaler Test${NC}"
echo -e " ${BLUE}→ System bereit für manuelle Tests und Entwicklung${NC}"
echo ""
echo -e "${GREEN}2)${NC} Vollständige Kiosk-Installation mit Remote-Zugang"
echo -e " ${BLUE}→ Komplette Produktionsinstallation mit automatischem Kiosk-Start${NC}"
echo -e " ${BLUE}→ RDP (root:744563017196A), SSH (user:raspberry), Firewall${NC}"
echo -e " ${BLUE}→ Automatischer Login und Kiosk-Modus beim Boot${NC}"
echo ""
echo -e "${GREEN}3)${NC} Beenden"
echo ""
echo -e "${CYAN}=================================================================${NC}"
echo -n "Ihre Wahl [1-3]: "
}
# =========================== INSTALLATIONS-MODI ===========================
install_dependencies_only() {
log "=== MODUS: ROBUSTE ABHÄNGIGKEITEN-INSTALLATION FÜR MANUELLES TESTEN ==="
# Grundlegende System-Validierung
check_root
check_system_resources
check_debian_system
check_internet_connection
# System-Konfiguration
configure_hostname
update_system
configure_network_security
# Core-Abhängigkeiten installieren
install_python_dependencies
install_nodejs_npm
install_ssl_certificates
install_python_packages
# Anwendung deployen
deploy_application
install_npm_dependencies
generate_ssl_certificate
# Services für manuelles Testen vorbereiten
install_systemd_services
enable_and_start_services
# Performance-Optimierungen auch für manuelles Testen
optimize_webapp_performance
optimize_static_assets
# Umfassende System-Tests
progress "Starte umfassende System-Tests..."
if test_application; then
success "✅ Alle System-Tests erfolgreich!"
else
warning "⚠️ System-Tests mit Problemen - System möglicherweise eingeschränkt funktionsfähig"
fi
# Cleanup
cleanup_old_files
success "✅ Robuste Abhängigkeiten-Installation abgeschlossen!"
log "📋 Installation Zusammenfassung:"
log " 🖥️ Hostname: raspberrypi"
log " 🐍 Python-Umgebung: Vollständig konfiguriert"
log " 🌐 Node.js: Installiert und optimiert"
log " 🔒 SSL-Zertifikate: Generiert und konfiguriert"
log " 📁 Anwendung: In $APP_DIR deployed"
log " ⚡ Performance: Optimiert für Raspberry Pi"
log " 🔧 Services: Installiert und gestartet"
info ""
info "🚀 System bereit für manuelle Tests und Entwicklung!"
info "🌐 HTTPS-Backend sollte verfügbar sein: $HTTPS_URL"
info "⚙️ Manuelle App-Start Alternative: cd /opt/myp && python3 app.py"
}
install_full_production_system() {
log "=== MODUS: VOLLSTÄNDIGE ROBUSTE KIOSK-INSTALLATION MIT REMOTE-ZUGANG ==="
# Umfassende System-Validierung
check_root
check_system_resources
check_debian_system
check_internet_connection
# System-Grundkonfiguration
configure_hostname
# Intelligente Abhängigkeiten-Installation
if [ ! -d "$APP_DIR" ] || [ ! -f "$APP_DIR/app.py" ]; then
warning "Anwendung noch nicht deployed - führe robuste Abhängigkeiten-Installation durch..."
# Vollständige Basis-Installation
update_system
configure_network_security
install_python_dependencies
install_nodejs_npm
install_ssl_certificates
install_python_packages
deploy_application
install_npm_dependencies
generate_ssl_certificate
else
info "Anwendung bereits deployed - überspringe Basis-Installation"
# Trotzdem Netzwerk-Sicherheit aktualisieren
configure_network_security
fi
# Desktop-Environments entfernen und minimale X11 installieren
remove_desktop_environments
install_minimal_x11
# Performance-Optimierungen für Raspberry Pi Webapp
optimize_webapp_performance
optimize_static_assets
# Remote-Zugang konfigurieren (robust)
install_remote_access
configure_firewall
# Kiosk-System konfigurieren
create_kiosk_user
configure_autologin
configure_kiosk_autostart
# Services installieren und aktivieren (robust)
install_systemd_services
enable_and_start_services
# Umfassende System-Tests
progress "Führe umfassende Produktions-System-Tests durch..."
local system_tests_passed=true
if test_application; then
success "✅ Anwendungs-Tests erfolgreich"
else
warning "⚠️ Anwendungs-Tests mit Problemen"
system_tests_passed=false
fi
if test_remote_access; then
success "✅ Remote-Zugang-Tests erfolgreich"
else
warning "⚠️ Remote-Zugang-Tests mit Problemen"
system_tests_passed=false
fi
# Aufräumen
cleanup_old_files
# Finale Status-Bewertung
if [ "$system_tests_passed" = true ]; then
success "✅ Vollständige robuste Kiosk-Installation erfolgreich abgeschlossen!"
else
warning "⚠️ Vollständige Kiosk-Installation mit Einschränkungen abgeschlossen"
info "→ Grundfunktionalität sollte verfügbar sein, manuelle Überprüfung empfohlen"
fi
log "📋 Vollständige Installation Zusammenfassung:"
log " 🖥️ Hostname: raspberrypi"
log " 🔐 Kiosk-Modus: Konfiguriert (startet beim nächsten Boot)"
log " 📡 SSH-Zugang: user:raspberry (Port 22)"
log " 🖥️ RDP-Zugang: root:744563017196A (Port 3389)"
log " 🔒 Firewall: Konfiguriert und aktiv"
log " ⚡ Performance: Optimiert für Raspberry Pi"
log " 🌐 HTTPS-Backend: $HTTPS_URL"
log " 🛡️ Sicherheit: IPv6 deaktiviert, erweiterte Netzwerk-Sicherheit"
info ""
success "🚀 Produktionssystem vollständig einsatzbereit!"
warning "⚠️ NEUSTART ERFORDERLICH für automatischen Kiosk-Start: sudo reboot"
}
# =========================== RDP & SSH ZUGANG ===========================
install_remote_access() {
log "=== INSTALLIERE REMOTE-ZUGANG (RDP & SSH) ==="
# SSH-Server installieren und konfigurieren
progress "Installiere und konfiguriere SSH-Server..."
apt-get install -y openssh-server || error "SSH-Server Installation fehlgeschlagen"
# SSH-Service aktivieren
systemctl enable ssh
systemctl start ssh
# SSH-Benutzer 'user' erstellen (falls nicht vorhanden)
if ! id "user" &>/dev/null; then
progress "Erstelle SSH-Benutzer: user"
useradd -m -s /bin/bash user || error "Kann SSH-Benutzer nicht erstellen"
echo "user:raspberry" | chpasswd || error "Kann Passwort für SSH-Benutzer nicht setzen"
usermod -aG sudo user 2>/dev/null || true
# pip-Konfiguration für SSH-Benutzer
mkdir -p "/home/user/.pip" 2>/dev/null || true
cat > "/home/user/.pip/pip.conf" << 'EOF'
[global]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
timeout = 60
retries = 3
[install]
break-system-packages = true
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
EOF
chown "user:user" "/home/user/.pip/pip.conf" 2>/dev/null || true
log "✅ SSH-Benutzer 'user' erstellt mit Passwort 'raspberry'"
else
info "SSH-Benutzer 'user' existiert bereits"
echo "user:raspberry" | chpasswd || warning "Konnte Passwort für SSH-Benutzer nicht aktualisieren"
fi
# RDP-Server (xrdp) installieren - vereinfachter Ansatz
progress "Installiere RDP-Server (xrdp) - vereinfachte Installation..."
# Alle bestehenden xrdp-Installationen entfernen
progress "Entferne vorherige xrdp-Installationen..."
systemctl stop xrdp xrdp-sesman 2>/dev/null || true
systemctl disable xrdp xrdp-sesman 2>/dev/null || true
apt-get remove --purge -y xrdp 2>/dev/null || true
rm -rf /etc/xrdp /var/log/xrdp* 2>/dev/null || true
# XFCE Desktop installieren (minimal)
progress "Installiere minimale XFCE-Umgebung..."
if ! apt-get install -y xfce4-session xfce4-panel xfce4-terminal xfce4-settings xfdesktop4 dbus-x11; then
warning "Minimale XFCE-Installation fehlgeschlagen - verwende Fallback..."
apt-get install -y xfce4 dbus-x11 || error "XFCE Installation fehlgeschlagen"
fi
# xrdp neu installieren
progress "Installiere xrdp neu..."
apt-get update
apt-get install -y xrdp || error "xrdp Installation fehlgeschlagen"
# Benutzer zur xrdp-Gruppe hinzufügen
usermod -aG xrdp root 2>/dev/null || true
if id "user" &>/dev/null; then
usermod -aG xrdp user 2>/dev/null || true
fi
# Erstelle minimale xrdp-Konfiguration
progress "Erstelle minimale xrdp-Konfiguration..."
# Backup der Original-Konfiguration
cp /etc/xrdp/xrdp.ini /etc/xrdp/xrdp.ini.original 2>/dev/null || true
# Sehr einfache xrdp.ini
cat > /etc/xrdp/xrdp.ini << 'EOF'
[Globals]
ini_version=1
fork=true
port=3389
tcp_nodelay=true
tcp_keepalive=true
security_layer=rdp
autorun=
allow_channels=true
allow_multimon=false
bitmap_cache=true
bitmap_compression=true
bulk_compression=false
max_bpp=24
new_cursors=true
use_fastpath=both
require_credentials=true
ask_for_reconnect_reason=false
enable_token_login=false
[Xorg]
name=Xorg
lib=libxup.so
username=ask
password=ask
ip=127.0.0.1
port=-1
code=20
EOF
# Einfache sesman.ini
cp /etc/xrdp/sesman.ini /etc/xrdp/sesman.ini.original 2>/dev/null || true
cat > /etc/xrdp/sesman.ini << 'EOF'
[Globals]
ListenAddress=127.0.0.1
ListenPort=3350
EnableUserWindowManager=true
UserWindowManager=startxfce4
DefaultWindowManager=startxfce4
[Security]
AllowRootLogin=true
MaxLoginRetry=4
AlwaysGroupCheck=false
[Sessions]
X11DisplayOffset=10
MaxSessions=10
KillDisconnected=false
IdleTimeLimit=0
DisconnectedTimeLimit=0
[Logging]
LogFile=xrdp-sesman.log
LogLevel=INFO
EnableSyslog=true
SyslogLevel=INFO
[Xorg]
param1=-bs
param2=-nolisten
param3=tcp
param4=-dpi
param5=96
EOF
# Erstelle .xsession für XFCE
progress "Konfiguriere XFCE-Sessions..."
# Root .xsession
cat > /root/.xsession << 'EOF'
#!/bin/bash
export XDG_SESSION_DESKTOP=xfce
export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share
export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg
exec startxfce4
EOF
chmod +x /root/.xsession
# User .xsession (falls user existiert)
if id "user" &>/dev/null; then
cat > /home/user/.xsession << 'EOF'
#!/bin/bash
export XDG_SESSION_DESKTOP=xfce
export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share
export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg
exec startxfce4
EOF
chown user:user /home/user/.xsession
chmod +x /home/user/.xsession
fi
# Root-Passwort setzen
progress "Setze Root-Passwort für RDP..."
echo "root:744563017196A" | chpasswd || error "Kann Root-Passwort nicht setzen"
# Log-Verzeichnisse erstellen mit korrekten Berechtigungen
progress "Erstelle Log-Verzeichnisse..."
mkdir -p /var/log
touch /var/log/xrdp.log /var/log/xrdp-sesman.log 2>/dev/null || true
chown xrdp:xrdp /var/log/xrdp*.log 2>/dev/null || true
chmod 644 /var/log/xrdp*.log 2>/dev/null || true
# Erstelle xrdp-Konfigurationsverzeichnisse
mkdir -p /etc/xrdp/cert /var/run/xrdp
chown xrdp:xrdp /etc/xrdp/cert /var/run/xrdp 2>/dev/null || true
# Services aktivieren und starten
progress "Starte xrdp-Services..."
# systemd daemon reload
systemctl daemon-reload
# Services aktivieren
systemctl enable xrdp-sesman
systemctl enable xrdp
# Services starten (sesman zuerst)
systemctl start xrdp-sesman
sleep 3
# Prüfe sesman-Status
if systemctl is-active --quiet xrdp-sesman; then
success "✅ xrdp-sesman erfolgreich gestartet"
# Jetzt xrdp starten
systemctl start xrdp
sleep 3
if systemctl is-active --quiet xrdp; then
success "✅ xrdp erfolgreich gestartet"
else
warning "⚠️ xrdp konnte nicht gestartet werden"
journalctl -u xrdp --no-pager -l | tail -10
fi
else
warning "⚠️ xrdp-sesman konnte nicht gestartet werden"
journalctl -u xrdp-sesman --no-pager -l | tail -10
fi
cd "$CURRENT_DIR"
# Finaler Status-Check
if systemctl is-active --quiet xrdp && systemctl is-active --quiet xrdp-sesman; then
log "✅ Remote-Zugang vollständig konfiguriert:"
log " 📡 SSH: user:raspberry (Port 22)"
log " 🖥️ RDP: root:744563017196A (Port 3389)"
log " 🖥️ RDP: user:raspberry (Port 3389)"
elif systemctl is-active --quiet ssh; then
log "✅ SSH-Zugang konfiguriert:"
log " 📡 SSH: user:raspberry (Port 22)"
warning "⚠️ RDP-Installation unvollständig"
info "Manuelle Überprüfung erforderlich:"
info " systemctl status xrdp"
info " systemctl status xrdp-sesman"
info " journalctl -u xrdp -f"
else
error "❌ Weder SSH noch RDP konnten konfiguriert werden"
fi
}
# =========================== FIREWALL KONFIGURATION ===========================
configure_firewall() {
log "=== KONFIGURIERE FIREWALL (firewalld) ==="
# firewalld installieren
progress "Installiere firewalld..."
apt-get install -y firewalld || error "firewalld Installation fehlgeschlagen"
# firewalld aktivieren und starten
systemctl enable firewalld
systemctl start firewalld
# Warte kurz bis firewalld vollständig gestartet ist
sleep 5
progress "Konfiguriere firewalld-Zonen und -Regeln..."
# Firewall-Status prüfen
if ! firewall-cmd --state >/dev/null 2>&1; then
error "firewalld ist nicht aktiv oder reagiert nicht"
fi
# Bestehende Zone entfernen falls vorhanden
progress "Entferne bestehende myp-backend Zone falls vorhanden..."
if firewall-cmd --permanent --get-zones | grep -q "myp-backend"; then
log "Entferne bestehende myp-backend Zone..."
firewall-cmd --permanent --delete-zone=myp-backend 2>/dev/null || true
firewall-cmd --reload
sleep 2
fi
# Zone neu erstellen
progress "Erstelle neue myp-backend Zone..."
if ! firewall-cmd --permanent --new-zone=myp-backend; then
error "Fehler beim Erstellen der myp-backend Zone"
fi
# Konfiguration neu laden
firewall-cmd --reload
sleep 2
# Erweiterte Netzwerk-Quellen definieren (nur IPv4)
progress "Füge Netzwerk-Quellen hinzu..."
firewall-cmd --permanent --zone=myp-backend --add-source=192.168.0.0/16 || error "Fehler beim Hinzufügen des 192.168.0.0/16 Netzwerks"
firewall-cmd --permanent --zone=myp-backend --add-source=127.0.0.1/32 || error "Fehler beim Hinzufügen von localhost"
# Lokaler Hostname "raspberrypi" hinzufügen
local local_hostname="raspberrypi"
progress "Füge lokalen Hostname hinzu: $local_hostname"
local local_ip=$(getent hosts "$local_hostname" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
if [ -n "$local_ip" ]; then
firewall-cmd --permanent --zone=myp-backend --add-source="$local_ip/32" 2>/dev/null || warning "Konnte lokalen Hostname nicht hinzufügen"
log "✅ Lokaler Hostname $local_hostname hinzugefügt: $local_ip"
else
info "Lokaler Hostname $local_hostname nicht auflösbar - wird beim nächsten Boot verfügbar sein"
fi
# Frontend-Server m040tbaraspi001 hinzufügen (falls auflösbar)
progress "Füge Frontend-Server hinzu: m040tbaraspi001"
local frontend_ip=$(getent hosts "m040tbaraspi001" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
if [ -n "$frontend_ip" ]; then
firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_ip/32" 2>/dev/null || warning "Konnte Frontend-Server IP nicht hinzufügen"
log "✅ Frontend-Server m040tbaraspi001 hinzugefügt: $frontend_ip"
else
# Versuche auch mit FQDN
local frontend_fqdn_ip=$(getent hosts "m040tbaraspi001.de040.corpintra.net" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
if [ -n "$frontend_fqdn_ip" ]; then
firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_fqdn_ip/32" 2>/dev/null || warning "Konnte Frontend-Server FQDN nicht hinzufügen"
log "✅ Frontend-Server m040tbaraspi001.de040.corpintra.net hinzugefügt: $frontend_fqdn_ip"
else
info "Frontend-Server m040tbaraspi001 nicht auflösbar - überspringe"
fi
fi
# Ports und Services hinzufügen
progress "Konfiguriere Ports und Services..."
# HTTPS für API & Kiosk zulassen
firewall-cmd --permanent --zone=myp-backend --add-port=443/tcp || error "Fehler beim Hinzufügen von Port 443"
# SSH für Wartung
firewall-cmd --permanent --zone=myp-backend --add-service=ssh || error "Fehler beim Hinzufügen des SSH-Service"
# RDP für Remote-Desktop
firewall-cmd --permanent --zone=myp-backend --add-port=3389/tcp || error "Fehler beim Hinzufügen von Port 3389"
# IPv6 in firewalld deaktivieren
progress "Deaktiviere IPv6 in firewalld..."
firewall-cmd --permanent --set-target=DROP --zone=public --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in public Zone deaktiviert werden"
firewall-cmd --permanent --set-target=DROP --zone=myp-backend --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in myp-backend Zone deaktiviert werden"
# Default-Zone setzen
progress "Setze Default-Zone..."
firewall-cmd --set-default-zone=myp-backend || error "Fehler beim Setzen der Default-Zone"
# Änderungen übernehmen
progress "Lade Firewall-Konfiguration neu..."
firewall-cmd --reload || error "Fehler beim Neuladen der Firewall-Konfiguration"
# Kurz warten und Status prüfen
sleep 3
# Firewall-Status anzeigen
progress "Firewall-Konfiguration:"
if firewall-cmd --list-all --zone=myp-backend 2>/dev/null; then
log "✅ Firewall-Konfiguration erfolgreich angezeigt"
else
warning "⚠️ Firewall-Status konnte nicht angezeigt werden"
fi
# Finale Validierung
progress "Validiere Firewall-Konfiguration..."
local validation_errors=0
# Prüfe ob Zone existiert
if ! firewall-cmd --get-zones | grep -q "myp-backend"; then
error "Zone myp-backend wurde nicht korrekt erstellt"
((validation_errors++))
fi
# Prüfe Default-Zone
if [ "$(firewall-cmd --get-default-zone)" != "myp-backend" ]; then
warning "Default-Zone ist nicht myp-backend"
((validation_errors++))
fi
# Prüfe Ports
if ! firewall-cmd --zone=myp-backend --query-port=443/tcp 2>/dev/null; then
warning "Port 443 nicht korrekt konfiguriert"
((validation_errors++))
fi
if ! firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then
warning "Port 3389 nicht korrekt konfiguriert"
((validation_errors++))
fi
if ! firewall-cmd --zone=myp-backend --query-service=ssh 2>/dev/null; then
warning "SSH-Service nicht korrekt konfiguriert"
((validation_errors++))
fi
if [ $validation_errors -eq 0 ]; then
log "✅ Firewall konfiguriert und validiert:"
log " 🔒 Zone: myp-backend (als Default gesetzt)"
log " 🌐 Netzwerk: 192.168.0.0/16 (nur IPv4)"
log " 🏠 Localhost: 127.0.0.1"
log " 🖥️ Lokaler Host: raspberrypi"
log " 📡 Frontend-Server: m040tbaraspi001"
log " 🔌 Ports: 443/tcp (HTTPS), 22/tcp (SSH), 3389/tcp (RDP)"
log " 🚫 IPv6 vollständig blockiert"
else
warning "⚠️ Firewall-Konfiguration mit $validation_errors Fehlern abgeschlossen"
info "System funktioniert möglicherweise trotzdem - manuelle Überprüfung empfohlen"
fi
}
# =========================== REMOTE-ZUGANG TESTEN ===========================
test_remote_access() {
log "=== TESTE REMOTE-ZUGANG ==="
# SSH-Service testen
progress "Teste SSH-Service..."
if systemctl is-active --quiet ssh; then
success "✅ SSH-Service läuft"
# SSH-Port testen
if ss -tlnp | grep -q ":22 "; then
success "✅ SSH-Port 22 ist offen"
else
warning "⚠️ SSH-Port 22 nicht erreichbar"
fi
else
warning "⚠️ SSH-Service läuft nicht"
fi
# RDP-Services testen
progress "Teste RDP-Services..."
local xrdp_sesman_status="❌"
local xrdp_status="❌"
if systemctl is-active --quiet xrdp-sesman; then
xrdp_sesman_status="✅"
success "✅ xrdp-sesman läuft"
else
warning "⚠️ xrdp-sesman läuft nicht"
fi
if systemctl is-active --quiet xrdp; then
xrdp_status="✅"
success "✅ xrdp läuft"
# RDP-Port testen
if ss -tlnp | grep -q ":3389 "; then
success "✅ RDP-Port 3389 ist offen"
else
warning "⚠️ RDP-Port 3389 nicht erreichbar"
fi
else
warning "⚠️ xrdp läuft nicht"
fi
# Firewall-Status testen
progress "Teste Firewall-Status..."
if systemctl is-active --quiet firewalld; then
success "✅ Firewall läuft"
# Prüfe ob Ports offen sind
if firewall-cmd --zone=myp-backend --query-port=22/tcp 2>/dev/null; then
success "✅ SSH-Port in Firewall freigegeben"
else
warning "⚠️ SSH-Port nicht in Firewall freigegeben"
fi
if firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then
success "✅ RDP-Port in Firewall freigegeben"
else
warning "⚠️ RDP-Port nicht in Firewall freigegeben"
fi
else
warning "⚠️ Firewall läuft nicht"
fi
# Netzwerk-Interface testen
progress "Teste Netzwerk-Konfiguration..."
local ip_address=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7}' | head -1 || echo "Unbekannt")
if [ "$ip_address" != "Unbekannt" ]; then
success "✅ Netzwerk-Interface aktiv: $ip_address"
info "Zugang-URLs:"
info " SSH: ssh user@$ip_address"
if [ "$xrdp_status" = "✅" ]; then
info " RDP: $ip_address:3389 (root:744563017196A oder user:raspberry)"
fi
else
warning "⚠️ Keine Netzwerk-IP ermittelt"
fi
# Status-Zusammenfassung
log "📊 Service-Status:"
log " SSH: $(systemctl is-active --quiet ssh && echo "✅ Aktiv" || echo "❌ Inaktiv")"
log " xrdp-sesman: $xrdp_sesman_status $(systemctl is-active --quiet xrdp-sesman && echo "Aktiv" || echo "Inaktiv")"
log " xrdp: $xrdp_status $(systemctl is-active --quiet xrdp && echo "Aktiv" || echo "Inaktiv")"
log "✅ Remote-Zugang-Test abgeschlossen"
}
# =========================== HOSTNAME KONFIGURATION ===========================
configure_hostname() {
log "=== KONFIGURIERE HOSTNAME ==="
local target_hostname="raspberrypi"
local current_hostname=$(hostname)
if [ "$current_hostname" != "$target_hostname" ]; then
progress "Setze Hostname von '$current_hostname' auf '$target_hostname'..."
# Hostname sofort setzen
hostnamectl set-hostname "$target_hostname" || error "Fehler beim Setzen des Hostnames"
# /etc/hostname aktualisieren
echo "$target_hostname" > /etc/hostname
# /etc/hosts aktualisieren
cp /etc/hosts /etc/hosts.backup
sed -i "s/127.0.1.1.*/127.0.1.1\t$target_hostname/" /etc/hosts
# Falls kein 127.0.1.1 Eintrag existiert, hinzufügen
if ! grep -q "127.0.1.1" /etc/hosts; then
echo "127.0.1.1 $target_hostname" >> /etc/hosts
fi
log "✅ Hostname erfolgreich auf '$target_hostname' gesetzt"
else
log "✅ Hostname bereits korrekt: '$target_hostname'"
fi
# Hostname-Auflösung testen
if getent hosts "$target_hostname" >/dev/null 2>&1; then
local resolved_ip=$(getent hosts "$target_hostname" | awk '{print $1}' | head -1)
log "✅ Hostname-Auflösung funktioniert: $target_hostname -> $resolved_ip"
else
warning "⚠️ Hostname-Auflösung für '$target_hostname' fehlgeschlagen"
fi
}
# =========================== WEBAPP PERFORMANCE-OPTIMIERUNG ===========================
optimize_webapp_performance() {
log "=== WEBAPP PERFORMANCE-OPTIMIERUNG FÜR RASPBERRY PI ==="
# Python/Flask spezifische Optimierungen
progress "Konfiguriere Python-Performance-Optimierungen..."
# Python Bytecode Optimierung aktivieren
cat > /etc/environment << 'EOF'
# Python Performance Optimierungen
PYTHONOPTIMIZE=2
PYTHONDONTWRITEBYTECODE=1
PYTHONUNBUFFERED=1
PYTHONHASHSEED=random
# Flask/SQLite Optimierungen
FLASK_ENV=production
FLASK_DEBUG=0
SQLITE_TMPDIR=/tmp
# Memory Optimierungen
MALLOC_ARENA_MAX=2
MALLOC_MMAP_THRESHOLD=131072
MALLOC_TRIM_THRESHOLD=131072
EOF
# Systemd Service-Optimierungen
progress "Optimiere Systemd-Services für bessere Performance..."
# Stoppe unnötige Services
local unnecessary_services=(
"bluetooth.service"
"hciuart.service"
"avahi-daemon.service"
"cups.service"
"cups-browsed.service"
"ModemManager.service"
"wpa_supplicant.service"
)
for service in "${unnecessary_services[@]}"; do
if systemctl is-enabled "$service" 2>/dev/null; then
systemctl disable "$service" 2>/dev/null || true
systemctl stop "$service" 2>/dev/null || true
log "✅ Service deaktiviert: $service"
fi
done
# Tmpfs für temporäre Dateien
progress "Konfiguriere tmpfs für bessere I/O Performance..."
cat >> /etc/fstab << 'EOF'
# MYP Performance Optimierungen - tmpfs für temporäre Dateien
tmpfs /tmp tmpfs defaults,noatime,nosuid,size=256m 0 0
tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=128m 0 0
tmpfs /var/log tmpfs defaults,noatime,nosuid,size=64m 0 0
EOF
# Logrotate für tmpfs-Logs konfigurieren
cat > /etc/logrotate.d/myp-tmpfs << 'EOF'
/var/log/*.log {
daily
missingok
rotate 2
compress
notifempty
create 0644 root root
copytruncate
}
EOF
# Systemd Journal Einstellungen optimieren
progress "Optimiere systemd Journal für bessere Performance..."
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/myp-performance.conf << 'EOF'
[Journal]
# Journal Optimierungen für Raspberry Pi
Storage=volatile
RuntimeMaxUse=32M
RuntimeKeepFree=16M
RuntimeMaxFileSize=8M
RuntimeMaxFiles=4
MaxRetentionSec=1day
MaxFileSec=1hour
ForwardToSyslog=no
ForwardToKMsg=no
ForwardToConsole=no
ForwardToWall=no
EOF
# Crontab für regelmäßige Cache-Bereinigung
progress "Installiere automatische Cache-Bereinigung..."
cat > /etc/cron.d/myp-cache-cleanup << 'EOF'
# MYP Cache und Memory Cleanup
# Alle 6 Stunden Cache bereinigen
0 */6 * * * root /bin/echo 3 > /proc/sys/vm/drop_caches
# Täglich um 3 Uhr temporäre Dateien bereinigen
0 3 * * * root /usr/bin/find /tmp -type f -atime +1 -delete 2>/dev/null
# Wöchentlich Python Cache bereinigen
0 2 * * 0 root /usr/bin/find /opt/myp -name "*.pyc" -delete 2>/dev/null
0 2 * * 0 root /usr/bin/find /opt/myp -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null
EOF
# Limits für bessere Ressourcen-Verwaltung
progress "Konfiguriere System-Limits..."
cat >> /etc/security/limits.conf << 'EOF'
# MYP Performance Limits
* soft nofile 65536
* hard nofile 65536
* soft nproc 32768
* hard nproc 32768
root soft nofile 65536
root hard nofile 65536
EOF
# Apache/Nginx entfernen falls vorhanden (Konflikt mit Flask)
progress "Entferne konfliktbehaftete Webserver..."
local webservers=("apache2" "nginx" "lighttpd")
for webserver in "${webservers[@]}"; do
if systemctl is-enabled "$webserver" 2>/dev/null; then
systemctl stop "$webserver" 2>/dev/null || true
systemctl disable "$webserver" 2>/dev/null || true
apt-get remove --purge -y "$webserver" 2>/dev/null || true
log "✅ Webserver entfernt: $webserver"
fi
done
log "✅ Webapp Performance-Optimierung abgeschlossen:"
log " 🚀 Python Bytecode-Optimierung aktiviert"
log " 💾 tmpfs für temporäre Dateien konfiguriert"
log " 📝 Journal-Logging optimiert"
log " 🧹 Automatische Cache-Bereinigung installiert"
log " ⚡ Unnötige Services deaktiviert"
log " 📊 System-Limits für bessere Performance gesetzt"
}
# =========================== CSS/JS OPTIMIERUNG ===========================
optimize_static_assets() {
log "=== STATISCHE DATEIEN OPTIMIERUNG ==="
if [ ! -d "$APP_DIR/static" ]; then
warning "Static-Ordner nicht gefunden - überspringe Asset-Optimierung"
return
fi
progress "Analysiere und optimiere CSS/JS Dateien..."
cd "$APP_DIR/static"
# Erstelle optimierte CSS-Datei durch Kombination kritischer Styles
progress "Erstelle optimierte CSS-Kombination..."
cat > css/critical.min.css << 'EOF'
/* Kritische Styles für ersten Seitenaufbau - Inline-optimiert */
*{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif;line-height:1.5}
.container{max-width:1200px;margin:0 auto;padding:0 1rem}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
.btn{display:inline-flex;align-items:center;padding:0.5rem 1rem;border:none;border-radius:0.375rem;font-weight:500;text-decoration:none;cursor:pointer;transition:all 0.15s}
.btn-primary{background:#3b82f6;color:white}.btn-primary:hover{background:#2563eb}
.card{background:white;border-radius:0.5rem;padding:1.5rem;box-shadow:0 1px 3px rgba(0,0,0,0.1)}
.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}
.hidden{display:none}.block{display:block}.inline-block{display:inline-block}
.text-sm{font-size:0.875rem}.text-lg{font-size:1.125rem}
.font-medium{font-weight:500}.font-bold{font-weight:700}
.text-gray-600{color:#4b5563}.text-gray-900{color:#111827}
.mb-4{margin-bottom:1rem}.mt-6{margin-top:1.5rem}.p-4{padding:1rem}
.w-full{width:100%}.h-full{height:100%}
@media(max-width:768px){.container{padding:0 0.5rem}.card{padding:1rem}}
EOF
# Erstelle minimale JavaScript-Loader
progress "Erstelle optimierten JavaScript-Loader..."
cat > js/loader.min.js << 'EOF'
/*Minimaler Async Loader für bessere Performance*/
(function(){var d=document,w=window;function loadCSS(href){var l=d.createElement('link');l.rel='stylesheet';l.href=href;l.media='print';l.onload=function(){this.media='all'};d.head.appendChild(l)}function loadJS(src,cb){var s=d.createElement('script');s.async=true;s.src=src;if(cb)s.onload=cb;d.head.appendChild(s)}w.loadAssets=function(){if(w.assetsLoaded)return;w.assetsLoaded=true;loadCSS('/static/css/tailwind.min.css');loadJS('/static/js/app.min.js')};if(d.readyState==='loading'){d.addEventListener('DOMContentLoaded',w.loadAssets)}else{w.loadAssets()}})();
EOF
# Service Worker für besseres Caching
progress "Erstelle optimierten Service Worker..."
cat > sw-optimized.js << 'EOF'
const CACHE_NAME = 'myp-webapp-v1';
const ASSETS_TO_CACHE = [
'/',
'/static/css/critical.min.css',
'/static/js/loader.min.js',
'/static/favicon.svg'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS_TO_CACHE))
);
});
self.addEventListener('fetch', event => {
if (event.request.destination === 'image' ||
event.request.url.includes('/static/')) {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
}
});
EOF
# Gzip-Kompression für statische Dateien
progress "Komprimiere statische Dateien..."
find . -name "*.css" -o -name "*.js" -o -name "*.html" | while read file; do
if [ -f "$file" ] && [ ! -f "$file.gz" ]; then
gzip -c "$file" > "$file.gz" 2>/dev/null || true
fi
done
cd "$CURRENT_DIR"
log "✅ Statische Dateien optimiert:"
log " 📦 Kritische CSS-Styles kombiniert"
log " ⚡ Asynchroner Asset-Loader erstellt"
log " 🗜️ Gzip-Kompression angewendet"
log " 🔄 Service Worker für Caching installiert"
}
# =========================== HAUPTPROGRAMM ===========================
main() {
# Erstelle Log-Datei
touch "$INSTALL_LOG" || true
while true; do
show_menu
read -r choice
case $choice in
1)
install_dependencies_only
echo ""
echo -n "Drücken Sie Enter um fortzufahren..."
read -r
;;
2)
install_full_production_system
echo ""
echo -n "Drücken Sie Enter um fortzufahren..."
read -r
;;
3)
log "Setup-Skript beendet"
exit 0
;;
*)
error "Ungültige Auswahl. Bitte wählen Sie 1-3."
;;
esac
done
}
# Skript starten
main "$@"