Projektarbeit-MYP/backend/app/install_raspberry_pi.sh

3404 lines
110 KiB
Bash

#!/bin/bash
# ===================================================================
# MYP Druckerverwaltung - Raspberry Pi Kiosk Installation
# Vollautomatische Installation für echten Kiosk-Modus ohne Escape
# Designed für Raspberry Pi OS, Ubuntu Server, Debian minimal
# ===================================================================
set -e # Bei Fehlern sofort beenden
# =========================== KONFIGURATION ===========================
KIOSK_USER="kiosk"
APP_USER="myp"
APP_DIR="/opt/myp-druckerverwaltung"
BACKUP_DIR="/opt/myp-backups"
CURRENT_DIR=""
INSTALL_LOG="/var/log/myp-kiosk-install.log"
CHROMIUM_BIN="" # Global verfügbar machen
# NEUE KONFIGURATION - Erweiterte Anforderungen
ROOT_PASSWORD="744563017196A"
HOSTNAME="raspberrypi"
# Desktop Environment Pakete die entfernt werden sollen
REMOVE_PACKAGES=(
"gnome*" "kde*" "xfce*" "lxde*" "mate*" "cinnamon*"
"lightdm" "gdm*" "xdm" "nodm"
"firefox*" "thunderbird*" "libreoffice*" "wolfram-engine"
"scratch*" "minecraft-pi" "sonic-pi" "idle*"
"vlc" "smplayer" "totem" "rhythmbox"
"gedit" "mousepad" "leafpad" "pluma"
"file-roller" "xarchiver" "ark"
"gimp" "inkscape" "blender"
"chromium-browser" # Alte Version entfernen
)
# Farben für Ausgabe
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
# ========================== LOGGING-SYSTEM ==========================
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"
}
# ========================== SYSTEM-CHECKS ==========================
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"
}
detect_system() {
log "Erkenne System-Umgebung..."
# Aktuelle Position ermitteln
CURRENT_DIR="$(pwd)"
log "Aktuelles Verzeichnis: $CURRENT_DIR"
# Prüfe ob wir uns im richtigen Verzeichnis befinden
if [ ! -f "$CURRENT_DIR/app.py" ]; then
error "app.py nicht gefunden in $CURRENT_DIR - Bitte im MYP-Projektverzeichnis ausführen!"
fi
# System-Info sammeln
info "System: $(uname -a)"
info "Distribution: $(lsb_release -d 2>/dev/null || cat /etc/os-release | head -1 || echo 'Unbekannt')"
info "Speicher: $(free -h | head -2 | tail -1)"
info "Festplatte: $(df -h / | tail -1)"
# Internetverbindung testen
if ! ping -c 1 google.com &> /dev/null; then
error "Keine Internetverbindung verfügbar!"
fi
# Minimal 2GB freier Speicher erforderlich
available_kb=$(df / | awk 'NR==2 {print $4}')
if [ "$available_kb" -lt 2000000 ]; then
error "Nicht genügend Speicherplatz! Mindestens 2GB erforderlich."
fi
log "✅ System-Checks erfolgreich"
}
# ========================== SYSTEM-GRUNDKONFIGURATION ==========================
setup_system_basics() {
log "=== PHASE 0: SYSTEM-GRUNDKONFIGURATION ==="
# Hostname setzen
progress "Setze Hostname auf '$HOSTNAME'..."
echo "$HOSTNAME" > /etc/hostname
sed -i "s/127.0.1.1.*/127.0.1.1\t$HOSTNAME/" /etc/hosts
hostnamectl set-hostname "$HOSTNAME" 2>/dev/null || true
# Root-Passwort setzen
progress "Setze Root-Passwort..."
echo "root:$ROOT_PASSWORD" | chpasswd
# Root-SSH-Zugang aktivieren (für Wartung)
if [ -f "/etc/ssh/sshd_config" ]; then
sed -i 's/#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
fi
# Zeitzone setzen
progress "Setze Zeitzone auf Europe/Berlin..."
timedatectl set-timezone Europe/Berlin 2>/dev/null || true
# Locales konfigurieren
progress "Konfiguriere deutsche Locales..."
if [ -f "/etc/locale.gen" ]; then
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen
locale-gen || true
update-locale LANG=de_DE.UTF-8 || true
fi
# Deutsche Tastaturlayout konfigurieren - VERBESSERTE VERSION
progress "Konfiguriere deutsches Tastaturlayout..."
# Sicherstellen dass keyboard-configuration installiert ist
if ! dpkg -l | grep -q keyboard-configuration; then
apt-get install -y keyboard-configuration console-setup console-data kbd
fi
# Debconf-Konfiguration für keyboard-configuration
echo "keyboard-configuration keyboard-configuration/layout select German" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/layoutcode string de" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/model select Generic 105-key (Intl) PC" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/modelcode string pc105" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/variant select German" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/variantcode string" | debconf-set-selections
# Rekonfiguriere keyboard-configuration
dpkg-reconfigure -f noninteractive keyboard-configuration
# /etc/default/keyboard für Console und X11
cat > "/etc/default/keyboard" << EOF
# Keyboard configuration file for Debian
# Deutsches Tastaturlayout
XKBMODEL="pc105"
XKBLAYOUT="de"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
EOF
# Console-Setup konfigurieren
cat > "/etc/default/console-setup" << EOF
# CONFIGURATION FILE FOR SETUPCON
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="guess"
FONTFACE="Fixed"
FONTSIZE="8x16"
VIDEOMODE=
EOF
# Console-Tastaturlayout sofort aktivieren
if command -v loadkeys &> /dev/null; then
loadkeys de 2>/dev/null || true
info "Console-Tastaturlayout auf Deutsch gesetzt"
fi
# Setupcon ausführen für Console-Setup
if command -v setupcon &> /dev/null; then
setupcon --force --save 2>/dev/null || true
info "Console-Setup konfiguriert"
fi
# X11-Tastaturlayout für Kiosk-Session vorbereiten
mkdir -p /etc/X11/xorg.conf.d
cat > "/etc/X11/xorg.conf.d/00-keyboard.conf" << EOF
# Deutsches Tastaturlayout für X11
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "de"
Option "XkbModel" "pc105"
Option "XkbVariant" ""
Option "XkbOptions" ""
EndSection
EOF
# Systemd localectl für moderne Debian-Systeme (mit Fehlerbehandlung)
if command -v localectl &> /dev/null; then
# Prüfe ob localectl funktioniert
if localectl status &> /dev/null; then
localectl set-keymap de 2>/dev/null || warning "localectl set-keymap fehlgeschlagen"
localectl set-x11-keymap de 2>/dev/null || warning "localectl set-x11-keymap fehlgeschlagen"
info "Tastaturlayout via localectl auf Deutsch gesetzt"
else
warning "localectl nicht funktional - verwende alternative Methoden"
# Alternative: Direkte Keymap-Datei setzen
echo "KEYMAP=de" > /etc/vconsole.conf 2>/dev/null || true
fi
else
warning "localectl nicht verfügbar - verwende legacy-Methoden"
# Legacy-Methode für ältere Systeme
echo "KEYMAP=de" > /etc/vconsole.conf 2>/dev/null || true
fi
# Keyboard-Services neu laden
systemctl reload-or-restart keyboard-setup 2>/dev/null || true
systemctl reload-or-restart console-setup 2>/dev/null || true
# Keymap-Dateien manuell prüfen und erstellen falls nötig
if [ ! -f "/usr/share/keymaps/i386/qwertz/de.kmap.gz" ] && [ ! -f "/usr/share/kbd/keymaps/i386/qwertz/de.map.gz" ]; then
warning "Deutsche Keymap-Dateien fehlen - installiere kbd-Paket"
apt-get install -y kbd console-data || true
fi
info "Deutsches Tastaturlayout global konfiguriert (Console + X11)"
log "✅ System-Grundkonfiguration abgeschlossen"
}
# ========================== SYSTEM-UPDATE ==========================
update_system() {
log "=== PHASE 0.5: SYSTEM-UPDATE ==="
progress "Aktualisiere Paketlisten..."
apt-get update -y || error "APT Update fehlgeschlagen"
progress "Upgrade bestehender Pakete..."
apt-get upgrade -y || warning "APT Upgrade teilweise fehlgeschlagen"
progress "Installiere essenzielle System-Tools..."
apt-get install -y \
ca-certificates \
gnupg \
lsb-release \
software-properties-common \
apt-transport-https \
curl \
wget \
git \
unzip \
nano \
htop \
rsync \
sudo \
cron \
logrotate \
tree \
zip \
keyboard-configuration \
console-setup \
console-data \
kbd \
locales \
|| error "Essenzielle Pakete Installation fehlgeschlagen"
# Dist-upgrade für Kernel-Updates
progress "Führe Distribution-Upgrade durch..."
apt-get dist-upgrade -y || warning "Dist-upgrade teilweise fehlgeschlagen"
log "✅ System-Update abgeschlossen"
}
# ========================== ZERTIFIKATE INSTALLIEREN ==========================
install_certificates() {
log "=== PHASE 0.8: ZERTIFIKATE-INSTALLATION ==="
progress "Aktualisiere CA-Zertifikate..."
apt-get install -y ca-certificates
update-ca-certificates
# Mozilla CA Bundle
progress "Installiere erweiterte Zertifikate..."
if ! wget -O /usr/local/share/ca-certificates/cacert.pem https://curl.se/ca/cacert.pem; then
warning "Mozilla CA Bundle Download fehlgeschlagen"
else
update-ca-certificates
fi
# SSL-Zertifikate für Python requests
if command -v python3 &> /dev/null; then
python3 -m pip install --upgrade certifi --break-system-packages 2>/dev/null || true
fi
log "✅ Zertifikate installiert und aktualisiert"
}
# ========================== VERZEICHNISSTRUKTUR ERSTELLEN ==========================
create_directory_structure() {
log "=== PHASE 1.5: VERZEICHNISSTRUKTUR ERSTELLEN ==="
progress "Erstelle MYP-Verzeichnisstruktur..."
# Hauptverzeichnisse
mkdir -p "$APP_DIR"
mkdir -p "$BACKUP_DIR"
# Upload-Ordner-Struktur
progress "Erstelle Upload-Verzeichnisse..."
UPLOAD_BASE="$APP_DIR/uploads"
CURRENT_YEAR=$(date +%Y)
CURRENT_MONTH=$(date +%m)
# Upload-Kategorien mit Jahres-/Monats-Struktur
for category in assets avatars backups guests jobs logs temp; do
mkdir -p "$UPLOAD_BASE/$category/$CURRENT_YEAR/$CURRENT_MONTH"
info "Erstellt: $UPLOAD_BASE/$category/$CURRENT_YEAR/$CURRENT_MONTH"
done
# Database-Verzeichnis
mkdir -p "$APP_DIR/database/backups"
# Log-Verzeichnisse
progress "Erstelle Log-Verzeichnisse..."
for log_cat in app auth errors jobs printers scheduler; do
mkdir -p "$APP_DIR/logs/$log_cat"
mkdir -p "/var/log/myp-$log_cat"
done
# Config-Verzeichnis
mkdir -p "$APP_DIR/config"
# Static Assets
mkdir -p "$APP_DIR/static/css"
mkdir -p "$APP_DIR/static/js"
mkdir -p "$APP_DIR/static/icons"
# Certificates
mkdir -p "$APP_DIR/certs"
log "✅ Verzeichnisstruktur erstellt"
}
# ========================== SYSTEM-BEREINIGUNG ==========================
cleanup_system() {
log "=== PHASE 1: SYSTEM-BEREINIGUNG ==="
# APT-Cache aktualisieren
progress "Aktualisiere Paketlisten..."
apt-get update -y || warning "APT Update teilweise fehlgeschlagen"
# Entferne unnötige Desktop-Umgebungen
progress "Entferne Desktop-Umgebungen und unnötige Software..."
for package in "${REMOVE_PACKAGES[@]}"; do
if dpkg -l | grep -q "^ii.*$package"; then
info "Entferne: $package"
apt-get purge -y "$package" 2>/dev/null || true
fi
done
# Aggressive Bereinigung
apt-get autoremove -y --purge
apt-get autoclean
# Stoppe unnötige Services
progress "Stoppe Desktop-Services..."
for service in gdm lightdm xdm nodm plymouth; do
systemctl stop "$service" 2>/dev/null || true
systemctl disable "$service" 2>/dev/null || true
done
log "✅ System-Bereinigung abgeschlossen"
}
# ========================== PAKETE INSTALLIEREN ==========================
install_packages() {
log "=== PHASE 2: SYSTEM-PAKETE INSTALLATION ==="
progress "Installiere Basis-Pakete..."
apt-get install -y \
curl wget git unzip \
python3 python3-pip python3-venv python3-dev \
build-essential libssl-dev libffi-dev \
sqlite3 nginx supervisor \
xorg xinit openbox \
xserver-xorg-video-all \
x11-xserver-utils xdotool unclutter \
pulseaudio alsa-utils \
fonts-liberation fonts-dejavu \
ca-certificates apt-transport-https \
systemd-timesyncd \
ufw fail2ban \
htop nano \
|| error "Basis-Pakete Installation fehlgeschlagen"
# Node.js installieren - VERBESSERTE VERSION
progress "Installiere Node.js mit mehreren Fallback-Methoden..."
# Prüfe ob Node.js bereits verfügbar ist
if command -v node &> /dev/null && command -v npm &> /dev/null; then
info "Node.js bereits verfügbar: $(node --version)"
info "NPM bereits verfügbar: $(npm --version)"
else
# Methode 1: NodeSource Repository (LTS)
progress "Versuche NodeSource LTS Repository..."
if curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs; then
log "✅ Node.js via NodeSource LTS installiert"
else
warning "NodeSource LTS fehlgeschlagen, versuche NodeSource 18.x..."
# Methode 2: NodeSource 18.x (stabil)
if curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs; then
log "✅ Node.js via NodeSource 18.x installiert"
else
warning "NodeSource fehlgeschlagen, versuche Standard-Repository..."
# Methode 3: Standard Repository
apt-get update && apt-get install -y nodejs npm || true
# Methode 4: Snap als Fallback
if ! command -v node &> /dev/null; then
warning "Standard-Repository fehlgeschlagen, versuche Snap..."
if command -v snap &> /dev/null || apt-get install -y snapd; then
snap install node --classic || true
fi
fi
# Methode 5: Manual Download als letzter Ausweg
if ! command -v node &> /dev/null; then
warning "Alle Repository-Methoden fehlgeschlagen, lade Node.js manuell herunter..."
NODE_VERSION="18.17.0"
ARCH=$(uname -m)
case $ARCH in
x86_64) NODE_ARCH="x64" ;;
armv7l) NODE_ARCH="armv7l" ;;
aarch64) NODE_ARCH="arm64" ;;
*) NODE_ARCH="x64" ;;
esac
cd /tmp
wget "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz" -O node.tar.xz || true
if [ -f "node.tar.xz" ]; then
tar -xf node.tar.xz
cp -r "node-v${NODE_VERSION}-linux-${NODE_ARCH}"/* /usr/local/
log "✅ Node.js manuell installiert"
fi
fi
fi
fi
# Finale Validierung
if command -v node &> /dev/null && command -v npm &> /dev/null; then
log "✅ Node.js erfolgreich installiert: $(node --version)"
log "✅ NPM erfolgreich installiert: $(npm --version)"
# NPM Global-Verzeichnis konfigurieren für bessere Berechtigungen
mkdir -p /usr/local/lib/npm-global
npm config set prefix '/usr/local/lib/npm-global'
echo 'export PATH=/usr/local/lib/npm-global/bin:$PATH' >> /etc/profile
export PATH=/usr/local/lib/npm-global/bin:$PATH
else
warning "⚠️ Node.js/NPM-Installation fehlgeschlagen - Node.js-Features werden übersprungen"
# Erstelle Dummy-npm-Kommando um Skript-Fehler zu vermeiden
cat > /usr/local/bin/npm << 'EOF'
#!/bin/bash
echo "NPM nicht verfügbar - Node.js-Installation fehlgeschlagen"
echo "Node.js-Abhängigkeiten werden übersprungen"
exit 0
EOF
chmod +x /usr/local/bin/npm
fi
fi
log "✅ System-Pakete installiert"
}
# ========================== CHROMIUM INSTALLATION ==========================
install_chromium() {
log "=== PHASE 3: CHROMIUM INSTALLATION ==="
progress "Installiere Chromium Browser..."
# Versuche verschiedene Installationsmethoden
if apt-get install -y chromium 2>/dev/null; then
CHROMIUM_BIN="/usr/bin/chromium"
log "✅ Chromium via APT installiert"
elif apt-get install -y chromium-browser 2>/dev/null; then
CHROMIUM_BIN="/usr/bin/chromium-browser"
log "✅ Chromium-Browser via APT installiert"
else
# Snap-Installation versuchen
warning "APT-Installation fehlgeschlagen, versuche Snap..."
if command -v snap &> /dev/null || (apt-get install -y snapd && systemctl enable --now snapd); then
snap install chromium
CHROMIUM_BIN="/snap/bin/chromium"
log "✅ Chromium via Snap installiert"
else
# Flatpak als letzter Ausweg
warning "Snap fehlgeschlagen, versuche Flatpak..."
if apt-get install -y flatpak && flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo; then
flatpak install -y flathub org.chromium.Chromium
CHROMIUM_BIN="flatpak run org.chromium.Chromium"
log "✅ Chromium via Flatpak installiert"
else
error "❌ Chromium konnte nicht installiert werden! Bitte manuell installieren."
fi
fi
fi
# Chromium-Binary validieren
if [[ "$CHROMIUM_BIN" == "flatpak"* ]]; then
# Flatpak-Spezialbehandlung
log "Chromium via Flatpak verfügbar"
elif [ ! -x "$CHROMIUM_BIN" ]; then
error "Chromium-Binary nicht ausführbar: $CHROMIUM_BIN"
fi
log "✅ Chromium-Installation abgeschlossen: $CHROMIUM_BIN"
}
# ========================== BENUTZER ERSTELLEN ==========================
create_users() {
log "=== PHASE 4: BENUTZER-ERSTELLUNG ==="
# App-Benutzer erstellen
progress "Erstelle App-Benutzer: $APP_USER"
if ! id "$APP_USER" &>/dev/null; then
if ! useradd -m -s /bin/bash "$APP_USER" 2>/dev/null; then
adduser --disabled-password --gecos "" "$APP_USER" || error "Kann App-Benutzer nicht erstellen"
fi
usermod -aG sudo "$APP_USER" 2>/dev/null || true
fi
# Kiosk-Benutzer erstellen
progress "Erstelle Kiosk-Benutzer: $KIOSK_USER"
if ! id "$KIOSK_USER" &>/dev/null; then
if ! useradd -m -s /bin/bash "$KIOSK_USER" 2>/dev/null; then
adduser --disabled-password --gecos "" "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen"
fi
# Kiosk-Benutzer zu Audio/Video-Gruppen hinzufügen
usermod -aG audio,video,input "$KIOSK_USER" 2>/dev/null || true
fi
log "✅ Benutzer erstellt: $APP_USER, $KIOSK_USER"
}
# ========================== ANWENDUNG INSTALLIEREN ==========================
install_application() {
log "=== PHASE 5: ANWENDUNGS-INSTALLATION ==="
# Anwendung kopieren
progress "Kopiere Anwendung von $CURRENT_DIR nach $APP_DIR"
rsync -av --exclude='.git' --exclude='__pycache__' --exclude='node_modules' "$CURRENT_DIR"/ "$APP_DIR/"
chown -R "$APP_USER:$APP_USER" "$APP_DIR"
# Wechsel ins Anwendungsverzeichnis
cd "$APP_DIR"
# DIREKTER PYTHON-PACKAGE INSTALL OHNE VENV - NEU!
progress "Installiere Python-Dependencies DIREKT (ohne Virtual Environment)..."
# Pip aktualisieren
python3 -m pip install --upgrade pip --break-system-packages
# Requirements installieren
if [ -f "requirements.txt" ]; then
info "Installiere aus requirements.txt..."
python3 -m pip install -r requirements.txt --break-system-packages
else
# Basis-Pakete installieren
info "Installiere Basis-Python-Pakete..."
python3 -m pip install --break-system-packages \
flask \
flask-login \
flask-wtf \
flask-limiter \
sqlalchemy \
werkzeug \
requests \
gunicorn \
bcrypt \
cryptography \
PyP100 \
python-dotenv \
Pillow \
schedule
fi
# ENGINE-IMPORT-FEHLER BEHEBEN
progress "Behebe Engine-Import-Problem..."
# Prüfe und korrigiere models.py
if [ -f "models.py" ]; then
# Backup erstellen
cp models.py models.py.backup
# Sicherstellen dass engine richtig importiert wird
if ! grep -q "from sqlalchemy import create_engine" models.py; then
sed -i '1i from sqlalchemy import create_engine' models.py
fi
# engine Variable definieren falls fehlt
if ! grep -q "^engine = " models.py; then
echo "" >> models.py
echo "# Engine für direkten Zugriff" >> models.py
echo "try:" >> models.py
echo " engine = create_optimized_engine()" >> models.py
echo "except:" >> models.py
echo " from sqlalchemy import create_engine" >> models.py
echo " engine = create_engine('sqlite:///database.db')" >> models.py
fi
fi
# app.py für engine-Kompatibilität erweitern
if [ -f "app.py" ]; then
# Backup erstellen
cp app.py app.py.backup
# Engine-Import sicherstellen
if ! grep -q "from models import.*engine" app.py; then
# Versuche engine zu importieren
if grep -q "from models import" app.py; then
sed -i '/from models import/s/$/,engine/' app.py 2>/dev/null || true
else
# Falls keine from models import Zeile existiert
if grep -q "import models" app.py; then
sed -i '/import models/a from models import engine' app.py
fi
fi
fi
# db-Variable für Kompatibilität
if ! grep -q "^db = engine" app.py; then
echo "" >> app.py
echo "# DB-Engine für Kompatibilität" >> app.py
echo "try:" >> app.py
echo " from models import engine" >> app.py
echo " db = engine" >> app.py
echo "except ImportError:" >> app.py
echo " from sqlalchemy import create_engine" >> app.py
echo " db = create_engine('sqlite:///database.db')" >> app.py
fi
fi
# Node.js Dependencies - VERBESSERTE VERSION
if [ -f "package.json" ]; then
progress "Installiere Node.js Dependencies..."
# Prüfe ob npm verfügbar ist
if command -v npm &> /dev/null && npm --version &> /dev/null; then
info "NPM verfügbar: $(npm --version)"
# Versuche npm install mit verschiedenen Methoden
if sudo -u "$APP_USER" npm install; then
log "✅ Node.js Dependencies installiert"
# Versuche CSS-Build falls Tailwind vorhanden
if [ -f "tailwind.config.js" ]; then
info "Tailwind-Konfiguration gefunden, versuche CSS-Build..."
if sudo -u "$APP_USER" npm run build:css; then
log "✅ CSS erfolgreich gebaut"
else
warning "⚠️ CSS-Build fehlgeschlagen - wird übersprungen"
# Fallback: Erstelle leere CSS-Datei
mkdir -p "$APP_DIR/static/css" || true
touch "$APP_DIR/static/css/tailwind.css" || true
chown "$APP_USER:$APP_USER" "$APP_DIR/static/css/tailwind.css" 2>/dev/null || true
fi
fi
else
warning "⚠️ npm install fehlgeschlagen, versuche Alternativen..."
# Alternative 1: npm install ohne Cache
if sudo -u "$APP_USER" npm install --no-cache; then
log "✅ Node.js Dependencies installiert (ohne Cache)"
elif sudo -u "$APP_USER" npm install --force; then
log "✅ Node.js Dependencies installiert (forciert)"
else
warning "⚠️ Alle npm-Installationsmethoden fehlgeschlagen"
warning "Node.js-Abhängigkeiten werden übersprungen"
# Erstelle leere CSS-Datei als Fallback
mkdir -p "$APP_DIR/static/css" || true
cat > "$APP_DIR/static/css/tailwind.css" << 'EOF'
/* Fallback CSS - NPM-Installation fehlgeschlagen */
body { font-family: system-ui, sans-serif; margin: 0; padding: 0; }
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/static/css/tailwind.css" 2>/dev/null || true
fi
fi
else
warning "⚠️ NPM nicht verfügbar - Node.js-Dependencies werden übersprungen"
info "Die Anwendung funktioniert auch ohne Node.js-Dependencies"
# Erstelle Fallback CSS-Datei
mkdir -p "$APP_DIR/static/css" || true
cat > "$APP_DIR/static/css/tailwind.css" << 'EOF'
/* Fallback CSS - NPM nicht verfügbar */
/* Basis-Styling für MYP-Anwendung */
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 0;
background: #f8f9fa;
}
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
.btn {
display: inline-block;
padding: 8px 16px;
background: #007bff;
color: white;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
}
.btn:hover { background: #0056b3; }
.alert {
padding: 12px;
margin: 10px 0;
border-radius: 4px;
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.alert-danger { background: #f8d7da; border-color: #f5c6cb; color: #721c24; }
.table { width: 100%; border-collapse: collapse; margin: 20px 0; }
.table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #dee2e6; }
.table th { background: #e9ecef; font-weight: 600; }
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
max-width: 400px;
}
.card {
background: white;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.text-center { text-align: center; }
.mt-4 { margin-top: 24px; }
.mb-4 { margin-bottom: 24px; }
.navbar {
background: #343a40;
color: white;
padding: 15px 0;
margin-bottom: 20px;
}
.navbar a { color: white; text-decoration: none; margin: 0 15px; }
.navbar a:hover { color: #adb5bd; }
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/static/css/tailwind.css" 2>/dev/null || true
log "✅ Fallback CSS-Datei erstellt"
fi
else
info "Keine package.json gefunden - Node.js-Dependencies werden übersprungen"
fi
# Datenbank initialisieren (DB-Import-Fehler behoben)
progress "Initialisiere Datenbank..."
python3 -c "
import sys
sys.path.insert(0, '$APP_DIR')
try:
from models import init_database, create_initial_admin
init_database()
create_initial_admin()
print('✅ Datenbank erfolgreich initialisiert')
except Exception as e:
print(f'⚠️ Datenbank-Initialisierung fehlgeschlagen: {str(e)}')
# Fallback: Erstelle leere Datenbank
import sqlite3
conn = sqlite3.connect('$APP_DIR/database.db')
conn.close()
print('✅ Fallback-Datenbank erstellt')
" || warning "Datenbank-Initialisierung fehlgeschlagen"
# Konfiguration erstellen
progress "Erstelle Anwendungskonfiguration..."
cat > "$APP_DIR/.env" << EOF
FLASK_ENV=production
SECRET_KEY=$(openssl rand -hex 32)
DATABASE_URL=sqlite:///database.db
HOST=0.0.0.0
PORT=5000
DEBUG=False
KIOSK_MODE=true
KIOSK_URL=http://localhost
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/.env"
log "✅ Anwendung installiert"
}
# ========================== DATEIBERECHTIGUNGEN SETZEN ==========================
set_file_permissions() {
log "=== PHASE 5.5: DATEIBERECHTIGUNGEN SETZEN ==="
progress "Setze korrekte Dateiberechtigungen..."
# Basis-Anwendungsverzeichnis
chown -R "$APP_USER:$APP_USER" "$APP_DIR"
chown -R "$APP_USER:$APP_USER" "$BACKUP_DIR"
# Verzeichnis-Berechtigungen
find "$APP_DIR" -type d -exec chmod 755 {} \;
find "$BACKUP_DIR" -type d -exec chmod 755 {} \;
# Datei-Berechtigungen
find "$APP_DIR" -type f -exec chmod 644 {} \;
# Ausführbare Dateien
if [ -f "$APP_DIR/app.py" ]; then
chmod 755 "$APP_DIR/app.py"
fi
# Upload-Ordner spezielle Berechtigungen
if [ -d "$APP_DIR/uploads" ]; then
chmod 755 "$APP_DIR/uploads"
find "$APP_DIR/uploads" -type d -exec chmod 755 {} \;
find "$APP_DIR/uploads" -type f -exec chmod 644 {} \;
# Prüfe ob www-data existiert, sonst verwende APP_USER
if id "www-data" &>/dev/null; then
chown -R "$APP_USER:www-data" "$APP_DIR/uploads"
else
warning "www-data-Benutzer nicht verfügbar - verwende $APP_USER:$APP_USER"
chown -R "$APP_USER:$APP_USER" "$APP_DIR/uploads"
fi
fi
# Log-Verzeichnisse
if [ -d "$APP_DIR/logs" ]; then
chmod 755 "$APP_DIR/logs"
find "$APP_DIR/logs" -type d -exec chmod 755 {} \;
find "$APP_DIR/logs" -type f -exec chmod 644 {} \;
chown -R "$APP_USER:$APP_USER" "$APP_DIR/logs"
fi
# Database-Verzeichnis
if [ -d "$APP_DIR/database" ]; then
chmod 755 "$APP_DIR/database"
find "$APP_DIR/database" -type f -exec chmod 644 {} \;
chown -R "$APP_USER:$APP_USER" "$APP_DIR/database"
fi
# Config-Dateien
if [ -f "$APP_DIR/.env" ]; then
chmod 600 "$APP_DIR/.env"
chown "$APP_USER:$APP_USER" "$APP_DIR/.env"
fi
# Static-Verzeichnis
if [ -d "$APP_DIR/static" ]; then
chmod 755 "$APP_DIR/static"
find "$APP_DIR/static" -type d -exec chmod 755 {} \;
find "$APP_DIR/static" -type f -exec chmod 644 {} \;
# Prüfe ob www-data existiert, sonst verwende APP_USER
if id "www-data" &>/dev/null; then
chown -R "$APP_USER:www-data" "$APP_DIR/static"
else
chown -R "$APP_USER:$APP_USER" "$APP_DIR/static"
fi
fi
# Templates-Verzeichnis
if [ -d "$APP_DIR/templates" ]; then
chmod 755 "$APP_DIR/templates"
find "$APP_DIR/templates" -type f -exec chmod 644 {} \;
chown -R "$APP_USER:$APP_USER" "$APP_DIR/templates"
fi
# System-Log-Verzeichnisse
for log_cat in app auth errors jobs printers scheduler; do
if [ -d "/var/log/myp-$log_cat" ]; then
chmod 755 "/var/log/myp-$log_cat"
fi
done
log "✅ Dateiberechtigungen gesetzt"
}
# ========================== KIOSK-KONFIGURATION ==========================
configure_kiosk() {
log "=== PHASE 6: ERWEITERTE KIOSK-KONFIGURATION ==="
# Sicherer Kiosk-Benutzer-Setup
KIOSK_HOME="/home/$KIOSK_USER"
progress "Konfiguriere Openbox für Kiosk..."
sudo -u "$KIOSK_USER" mkdir -p "$KIOSK_HOME/.config/openbox"
# Openbox-Konfiguration für maximale Sicherheit
cat > "$KIOSK_HOME/.config/openbox/rc.xml" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<openbox_config xmlns="http://openbox.org/3.4/rc">
<resistance>
<strength>10</strength>
<screen_edge_strength>20</screen_edge_strength>
</resistance>
<focus>
<focusNew>yes</focusNew>
<followMouse>no</followMouse>
<focusLast>yes</focusLast>
<underMouse>no</underMouse>
<focusDelay>200</focusDelay>
<raiseOnFocus>no</raiseOnFocus>
</focus>
<placement>
<policy>Smart</policy>
<center>yes</center>
<monitor>Primary</monitor>
<primaryMonitor>1</primaryMonitor>
</placement>
<theme>
<name>Clearlooks</name>
<titleLayout>NLIMC</titleLayout>
<keepBorder>yes</keepBorder>
<animateIconify>yes</animateIconify>
<font place="ActiveWindow">
<name>sans</name>
<size>8</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
</theme>
<desktops>
<number>1</number>
<firstdesk>1</firstdesk>
<names>
<name>Kiosk</name>
</names>
<popupTime>875</popupTime>
</desktops>
<resize>
<drawContents>yes</drawContents>
<popupShow>Nonpixel</popupShow>
<popupPosition>Center</popupPosition>
<popupFixedPosition>
<x>10</x>
<y>10</y>
</popupFixedPosition>
</resize>
<dock>
<position>TopLeft</position>
<floatingX>0</floatingX>
<floatingY>0</floatingY>
<noStrut>no</noStrut>
<stacking>Above</stacking>
<direction>Vertical</direction>
<autoHide>no</autoHide>
<hideDelay>300</hideDelay>
<showDelay>300</showDelay>
<moveButton>Middle</moveButton>
</dock>
<keyboard>
<!-- ALLE SHORTCUTS DEAKTIVIERT FÜR KIOSK-SICHERHEIT -->
</keyboard>
<mouse>
<dragThreshold>3</dragThreshold>
<doubleClickTime>200</doubleClickTime>
<screenEdgeWarpTime>400</screenEdgeWarpTime>
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
</mouse>
<menu>
<!-- KEIN MENU FÜR KIOSK -->
</menu>
<applications>
<application name="chromium*">
<decor>no</decor>
<shade>no</shade>
<position force="yes">
<x>0</x>
<y>0</y>
</position>
<size>
<width>100%</width>
<height>100%</height>
</size>
<fullscreen>yes</fullscreen>
<maximized>yes</maximized>
<skip_pager>yes</skip_pager>
<skip_taskbar>yes</skip_taskbar>
</application>
</applications>
</openbox_config>
EOF
# ERWEITERTE KIOSK-KONFIGURATION - Basierend auf Best Practices
progress "Erstelle erweiterte Kiosk-Skripte..."
# Haupt-Kiosk-Skript mit Raspberry Pi Optimierungen
cat > "$KIOSK_HOME/start-kiosk.sh" << EOF
#!/bin/bash
# ===================================================================
# MYP Kiosk-Starter - Optimiert für Raspberry Pi
# Basierend auf: https://mpascucci.github.io/tutorial/rpi/
# Und: https://blog.kngstn.eu/article/2023-09-22-raspberrypi-als-web-kiosk/
# ===================================================================
export DISPLAY=:0
# Logging für Debugging
exec > >(tee -a /var/log/kiosk-session.log) 2>&1
echo "\$(date): Kiosk-Session gestartet für Benutzer $KIOSK_USER"
# ===== RASPBERRY PI SPEZIFISCHE OPTIMIERUNGEN =====
# GPU Memory Split optimieren (falls verfügbar)
if [ -f "/boot/config.txt" ]; then
# Prüfe GPU Memory Split
GPU_MEM=\$(vcgencmd get_mem gpu 2>/dev/null | cut -d= -f2 | cut -d'M' -f1)
if [ "\$GPU_MEM" -lt 128 ]; then
echo "Warnung: GPU Memory Split zu niedrig (\${GPU_MEM}M). Empfohlen: 128M+"
fi
fi
# WLAN Power Save deaktivieren (Raspberry Pi spezifisch)
if iwconfig wlan0 2>/dev/null | grep -q "Power Management:on"; then
echo "Deaktiviere WLAN Power Save..."
sudo iwconfig wlan0 power off 2>/dev/null || true
fi
# ===== BILDSCHIRM-KONFIGURATION =====
# Bildschirmschoner komplett deaktivieren
xset s off
xset s noblank
xset s noexpose
xset -dpms
# Bildschirm-Blanking in /boot/cmdline.txt verhindern
if ! grep -q "consoleblank=0" /boot/cmdline.txt 2>/dev/null; then
echo "Hinweis: consoleblank=0 sollte in /boot/cmdline.txt gesetzt werden"
fi
# ===== MAUS UND EINGABE =====
# Mauszeiger verstecken mit unclutter
if command -v unclutter &> /dev/null; then
unclutter -idle 0.5 -root &
echo "Mauszeiger wird nach 0.5s versteckt"
else
echo "Warnung: unclutter nicht installiert"
fi
# Virtuelle Tastatur deaktivieren
killall onboard 2>/dev/null || true
killall matchbox-keyboard 2>/dev/null || true
# ===== CHROMIUM VORBEREITUNG =====
# Chromium Crash-Flags bereinigen (wichtig für Raspberry Pi)
CHROMIUM_CONFIG_DIR="$KIOSK_HOME/.config/chromium/Default"
if [ -f "\$CHROMIUM_CONFIG_DIR/Preferences" ]; then
sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' "\$CHROMIUM_CONFIG_DIR/Preferences" 2>/dev/null || true
sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' "\$CHROMIUM_CONFIG_DIR/Preferences" 2>/dev/null || true
echo "Chromium Crash-Flags bereinigt"
fi
# ===== WARTE AUF ANWENDUNG =====
echo "Warte auf MYP-Anwendung..."
WAIT_COUNT=0
while ! curl -s http://localhost:5000 > /dev/null; do
echo "Warte auf MYP-Anwendung... (\$WAIT_COUNT/60)"
sleep 2
WAIT_COUNT=\$((WAIT_COUNT + 1))
if [ \$WAIT_COUNT -gt 60 ]; then
echo "FEHLER: MYP-Anwendung nach 120s nicht erreichbar!"
# Fallback: Zeige Fehlerseite
echo "<html><body><h1>MYP-System wird geladen...</h1><p>Bitte warten Sie einen Moment.</p><script>setTimeout(function(){location.reload();}, 5000);</script></body></html>" > /tmp/loading.html
break
fi
done
# ===== CHROMIUM KIOSK-MODUS MIT RASPBERRY PI OPTIMIERUNGEN =====
# Raspberry Pi spezifische Chromium-Flags
CHROMIUM_FLAGS="
--kiosk
--no-sandbox
--disable-web-security
--disable-features=TranslateUI,BlinkGenPropertyTrees
--disable-ipc-flooding-protection
--disable-renderer-backgrounding
--disable-backgrounding-occluded-windows
--disable-background-timer-throttling
--disable-background-networking
--disable-breakpad
--disable-component-extensions-with-background-pages
--disable-dev-shm-usage
--disable-extensions
--disable-hang-monitor
--disable-popup-blocking
--disable-prompt-on-repost
--disable-sync
--disable-translate
--disable-infobars
--disable-session-crashed-bubble
--disable-restore-session-state
--disable-crash-reporter
--noerrdialogs
--no-first-run
--no-default-browser-check
--autoplay-policy=no-user-gesture-required
--start-fullscreen
--window-position=0,0
--window-size=1920,1080
--user-data-dir=$KIOSK_HOME/.chromium-kiosk
--disable-features=VizDisplayCompositor
--enable-features=OverlayScrollbar
--disable-gpu-sandbox
--disable-software-rasterizer
--ignore-certificate-errors
--ignore-ssl-errors
--ignore-certificate-errors-spki-list
--ignore-ssl-errors-list
--disable-logging
--silent-debugger-extension-api
--disable-default-apps
--disable-background-mode
--app-auto-launched
--no-startup-window
--force-device-scale-factor=1.0
--disable-pinch
--overscroll-history-navigation=0
"
# Raspberry Pi Hardware-spezifische Optimierungen
if grep -q "Raspberry Pi" /proc/cpuinfo 2>/dev/null; then
echo "Raspberry Pi erkannt - aktiviere Hardware-Optimierungen"
CHROMIUM_FLAGS="\$CHROMIUM_FLAGS
--disable-gpu-compositing
--enable-gpu-rasterization
--disable-smooth-scrolling
--disable-2d-canvas-image-chromium
--disable-accelerated-2d-canvas
--num-raster-threads=2
--enable-zero-copy
"
fi
# URL bestimmen
if curl -s http://localhost:5000 > /dev/null; then
KIOSK_URL="http://localhost:5000"
else
KIOSK_URL="file:///tmp/loading.html"
fi
echo "Starte Chromium im Kiosk-Modus mit URL: \$KIOSK_URL"
# Chromium mit Restart-Loop starten (wichtig für Stabilität)
while true; do
echo "\$(date): Starte Chromium..."
\$CHROMIUM_BIN \$CHROMIUM_FLAGS "\$KIOSK_URL"
EXIT_CODE=\$?
echo "\$(date): Chromium beendet mit Exit-Code: \$EXIT_CODE"
# Bei normalem Exit (0) oder Kiosk-Exit (15) nicht neustarten
if [ \$EXIT_CODE -eq 0 ] || [ \$EXIT_CODE -eq 15 ]; then
echo "Chromium normal beendet - Kiosk-Modus verlassen"
break
fi
# Bei Crash: Kurz warten und neustarten
echo "Chromium-Crash erkannt - Neustart in 3 Sekunden..."
sleep 3
# Bereinige Chromium-Prozesse
pkill -f chromium 2>/dev/null || true
sleep 1
done
echo "\$(date): Kiosk-Session beendet"
EOF
# LXDE Autostart-Konfiguration (Alternative Methode)
progress "Konfiguriere LXDE Autostart..."
sudo -u "$KIOSK_USER" mkdir -p "$KIOSK_HOME/.config/lxsession/LXDE-pi"
cat > "$KIOSK_HOME/.config/lxsession/LXDE-pi/autostart" << EOF
#################################################
# LXDE-pi autostart script für MYP Kiosk #
# Basierend auf: https://mpascucci.github.io/tutorial/rpi/
#################################################
# Bildschirmschoner deaktivieren
@xset s noblank
@xset s off
@xset -dpms
# Mauszeiger verstecken
@unclutter -idle 0.5 -root
# Kiosk-Anwendung starten
@bash $KIOSK_HOME/start-kiosk.sh
EOF
# Desktop-Autostart-Datei (systemd-kompatibel)
progress "Erstelle Desktop-Autostart-Datei..."
sudo -u "$KIOSK_USER" mkdir -p "$KIOSK_HOME/.config/autostart"
cat > "$KIOSK_HOME/.config/autostart/myp-kiosk.desktop" << EOF
[Desktop Entry]
Type=Application
Name=MYP Kiosk Application
Comment=Startet die MYP Kiosk-Anwendung automatisch
Exec=/bin/bash $KIOSK_HOME/start-kiosk.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
StartupNotify=false
Categories=System;
EOF
# Skripte ausführbar machen
chmod +x "$KIOSK_HOME/start-kiosk.sh"
chmod +x "$KIOSK_HOME/.config/lxsession/LXDE-pi/autostart"
chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.config"
chown "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/start-kiosk.sh"
log "✅ Erweiterte Kiosk-Konfiguration erstellt"
}
# ========================== RASPBERRY PI OPTIMIERUNGEN ==========================
optimize_raspberry_pi() {
log "=== PHASE 6.2: RASPBERRY PI OPTIMIERUNGEN ==="
# Prüfe ob es sich um einen Raspberry Pi handelt
if ! grep -q "Raspberry Pi" /proc/cpuinfo 2>/dev/null; then
info "Kein Raspberry Pi erkannt - überspringe Pi-spezifische Optimierungen"
return 0
fi
progress "Raspberry Pi erkannt - aktiviere Hardware-Optimierungen..."
# ===== BOOT-KONFIGURATION OPTIMIEREN =====
progress "Optimiere Boot-Konfiguration..."
# /boot/config.txt Optimierungen
if [ -f "/boot/config.txt" ]; then
# Backup erstellen
cp /boot/config.txt /boot/config.txt.backup
# GPU Memory Split für bessere Browser-Performance
if ! grep -q "gpu_mem=" /boot/config.txt; then
echo "" >> /boot/config.txt
echo "# MYP Kiosk Optimierungen" >> /boot/config.txt
echo "gpu_mem=128" >> /boot/config.txt
info "GPU Memory Split auf 128MB gesetzt"
fi
# Disable Rainbow Splash
if ! grep -q "disable_splash=1" /boot/config.txt; then
echo "disable_splash=1" >> /boot/config.txt
fi
# HDMI Force Hotplug für bessere Display-Kompatibilität
if ! grep -q "hdmi_force_hotplug=1" /boot/config.txt; then
echo "hdmi_force_hotplug=1" >> /boot/config.txt
fi
# Disable Overscan für Kiosk-Displays
if ! grep -q "disable_overscan=1" /boot/config.txt; then
echo "disable_overscan=1" >> /boot/config.txt
fi
# Audio über HDMI aktivieren
if ! grep -q "hdmi_drive=2" /boot/config.txt; then
echo "hdmi_drive=2" >> /boot/config.txt
fi
info "Boot-Konfiguration optimiert"
fi
# /boot/cmdline.txt Optimierungen
if [ -f "/boot/cmdline.txt" ]; then
# Backup erstellen
cp /boot/cmdline.txt /boot/cmdline.txt.backup
# Console Blanking deaktivieren
if ! grep -q "consoleblank=0" /boot/cmdline.txt; then
sed -i 's/$/ consoleblank=0/' /boot/cmdline.txt
info "Console Blanking deaktiviert"
fi
# Logo deaktivieren für schnelleren Boot
if ! grep -q "logo.nologo" /boot/cmdline.txt; then
sed -i 's/$/ logo.nologo/' /boot/cmdline.txt
fi
# Quiet Boot für saubere Kiosk-Erfahrung
if ! grep -q "quiet" /boot/cmdline.txt; then
sed -i 's/$/ quiet/' /boot/cmdline.txt
fi
fi
# ===== WLAN POWER MANAGEMENT DEAKTIVIEREN =====
progress "Deaktiviere WLAN Power Management..."
# Systemd-Service für WLAN Power Management
cat > "/etc/systemd/system/disable-wifi-power-management.service" << 'EOF'
[Unit]
Description=Disable WiFi Power Management
After=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'iwconfig wlan0 power off 2>/dev/null || true'
[Install]
WantedBy=multi-user.target
EOF
systemctl enable disable-wifi-power-management.service
# NetworkManager Konfiguration (falls vorhanden)
if [ -d "/etc/NetworkManager/conf.d" ]; then
cat > "/etc/NetworkManager/conf.d/default-wifi-powersave-on.conf" << 'EOF'
[connection]
wifi.powersave = 2
EOF
info "NetworkManager WLAN Power Save deaktiviert"
fi
# ===== ENERGIESPARMODUS KOMPLETT DEAKTIVIEREN =====
progress "Deaktiviere Energiesparmodus..."
# LightDM Konfiguration erweitern
if [ -f "/etc/lightdm/lightdm.conf" ]; then
# Backup erstellen
cp /etc/lightdm/lightdm.conf /etc/lightdm/lightdm.conf.backup
# X-Server Kommando mit DPMS-Deaktivierung
if ! grep -q "xserver-command=X -s 0 -dpms" /etc/lightdm/lightdm.conf; then
sed -i '/^\[Seat:\*\]/a xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf
info "X-Server Energiesparmodus deaktiviert"
fi
fi
# ===== SYSTEMD POWER MANAGEMENT =====
progress "Konfiguriere systemd Power Management..."
# Logind-Konfiguration für Kiosk
mkdir -p /etc/systemd/logind.conf.d
cat > "/etc/systemd/logind.conf.d/kiosk-power.conf" << 'EOF'
[Login]
# Verhindere Suspend/Hibernate im Kiosk-Modus
HandlePowerKey=ignore
HandleSuspendKey=ignore
HandleHibernateKey=ignore
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
# Idle-Verhalten für Kiosk
IdleAction=ignore
IdleActionSec=infinity
# Session-Management
KillUserProcesses=no
UserStopDelaySec=10
EOF
# ===== RASPBERRY PI SPEZIFISCHE PAKETE =====
progress "Installiere Raspberry Pi spezifische Tools..."
# Raspberry Pi Tools (falls verfügbar)
apt-get install -y \
libraspberrypi-bin \
raspberrypi-kernel-headers \
wireless-tools \
bc \
2>/dev/null || warning "Einige Pi-spezifische Pakete nicht verfügbar"
# ===== TEMPERATUR-MONITORING =====
progress "Konfiguriere Temperatur-Monitoring..."
# Temperatur-Check-Skript
cat > "/usr/local/bin/pi-temp-check" << 'EOF'
#!/bin/bash
# Raspberry Pi Temperatur-Check für Kiosk-System
TEMP=$(vcgencmd measure_temp 2>/dev/null | cut -d= -f2 | cut -d"'" -f1)
if [ -n "$TEMP" ]; then
echo "$(date): CPU Temperatur: ${TEMP}°C" >> /var/log/pi-temperature.log
# Warnung bei hoher Temperatur
if (( $(echo "$TEMP > 70" | bc -l) )); then
echo "$(date): WARNUNG - Hohe CPU Temperatur: ${TEMP}°C" >> /var/log/pi-temperature.log
logger "Raspberry Pi: Hohe CPU Temperatur: ${TEMP}°C"
fi
# Kritische Temperatur
if (( $(echo "$TEMP > 80" | bc -l) )); then
echo "$(date): KRITISCH - Sehr hohe CPU Temperatur: ${TEMP}°C" >> /var/log/pi-temperature.log
logger "Raspberry Pi: KRITISCHE Temperatur: ${TEMP}°C"
fi
fi
EOF
chmod +x /usr/local/bin/pi-temp-check
# Cron-Job für Temperatur-Monitoring
cat > "/etc/cron.d/pi-temperature" << 'EOF'
# Raspberry Pi Temperatur-Monitoring alle 5 Minuten
*/5 * * * * root /usr/local/bin/pi-temp-check
EOF
# ===== PERFORMANCE-OPTIMIERUNGEN =====
progress "Aktiviere Performance-Optimierungen..."
# Swappiness reduzieren für bessere Performance
echo "vm.swappiness=10" >> /etc/sysctl.conf
# Dirty Ratio optimieren
echo "vm.dirty_ratio=15" >> /etc/sysctl.conf
echo "vm.dirty_background_ratio=5" >> /etc/sysctl.conf
# ===== UNCLUTTER INSTALLATION =====
progress "Installiere unclutter für Mauszeiger-Verstecken..."
apt-get install -y unclutter || warning "unclutter Installation fehlgeschlagen"
# ===== CHROMIUM OPTIMIERUNGEN FÜR RASPBERRY PI =====
progress "Konfiguriere Chromium für Raspberry Pi..."
# Chromium GPU-Konfiguration
mkdir -p /etc/chromium-browser/policies/managed
cat > "/etc/chromium-browser/policies/managed/kiosk-policy.json" << 'EOF'
{
"DefaultBrowserSettingEnabled": false,
"BackgroundModeEnabled": false,
"BookmarkBarEnabled": false,
"BrowserSignin": 0,
"DefaultNotificationsSetting": 2,
"DefaultGeolocationSetting": 2,
"DefaultMediaStreamSetting": 2,
"PasswordManagerEnabled": false,
"AutofillAddressEnabled": false,
"AutofillCreditCardEnabled": false,
"TranslateEnabled": false,
"SpellCheckServiceEnabled": false,
"SearchSuggestEnabled": false,
"ImportBookmarks": false,
"ImportHistory": false,
"ImportSavedPasswords": false,
"ImportSearchEngine": false,
"MetricsReportingEnabled": false,
"UserFeedbackAllowed": false
}
EOF
info "Chromium-Richtlinien für Kiosk-Modus konfiguriert"
log "✅ Raspberry Pi Optimierungen abgeschlossen"
}
# ========================== DNS UND NETZWERK OPTIMIERUNG ==========================
configure_dns_and_network() {
log "=== PHASE 6.3: DNS UND NETZWERK OPTIMIERUNG ==="
progress "Konfiguriere intelligente DNS-Auflösung..."
# ===== IPv6 DEAKTIVIEREN =====
progress "Deaktiviere IPv6 systemweit..."
# Kernel-Parameter für IPv6-Deaktivierung
cat >> /etc/sysctl.conf << 'EOF'
# IPv6 deaktivieren für Kiosk-System
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
# IPv6 sofort deaktivieren
sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1
sysctl -w net.ipv6.conf.lo.disable_ipv6=1
# IPv6 in GRUB deaktivieren (falls vorhanden)
if [ -f "/etc/default/grub" ]; then
if ! grep -q "ipv6.disable=1" /etc/default/grub; then
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' /etc/default/grub
update-grub 2>/dev/null || true
fi
fi
# IPv6 in /boot/cmdline.txt deaktivieren (Raspberry Pi)
if [ -f "/boot/cmdline.txt" ]; then
if ! grep -q "ipv6.disable=1" /boot/cmdline.txt; then
sed -i 's/$/ ipv6.disable=1/' /boot/cmdline.txt
fi
fi
info "IPv6 systemweit deaktiviert"
# ===== UNBOUND DNS RESOLVER INSTALLIEREN =====
progress "Installiere Unbound DNS Resolver..."
apt-get install -y unbound unbound-host dnsutils || error "Unbound Installation fehlgeschlagen"
# ===== DNS KONFIGURATION MIT PRIORITÄTEN =====
progress "Konfiguriere DNS mit intelligenten Prioritäten..."
# Unbound Hauptkonfiguration
cat > "/etc/unbound/unbound.conf" << 'EOF'
# Unbound DNS Resolver Konfiguration für MYP Kiosk
# Intelligente DNS-Auflösung mit Fallback-Mechanismen
server:
# Basis-Konfiguration
verbosity: 1
interface: 127.0.0.1
port: 53
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
# Sicherheit
chroot: ""
username: "unbound"
directory: "/etc/unbound"
logfile: "/var/log/unbound.log"
use-syslog: yes
log-queries: no
log-replies: no
# Performance
num-threads: 2
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
msg-cache-size: 64m
rrset-cache-size: 128m
cache-max-ttl: 86400
cache-min-ttl: 300
# Netzwerk-Einstellungen
outgoing-range: 4096
num-queries-per-thread: 2048
so-rcvbuf: 4m
so-sndbuf: 4m
# Lokale Netzwerke erlauben
access-control: 127.0.0.0/8 allow
access-control: 192.168.0.0/16 allow
access-control: 10.0.0.0/8 allow
access-control: 172.16.0.0/12 allow
# Root Hints
root-hints: "/var/lib/unbound/root.hints"
# DNSSEC
auto-trust-anchor-file: "/var/lib/unbound/root.key"
# Lokale Auflösung
private-address: 192.168.0.0/16
private-address: 172.16.0.0/12
private-address: 10.0.0.0/8
private-address: 127.0.0.0/8
# Upstream DNS Server mit Prioritäten
# 1. Prio: Router DNS (wird dynamisch gesetzt)
# 2. Prio: Google DNS
# 3. Prio: Cloudflare DNS
# 4. Prio: Custom DNS Server
forward-zone:
name: "."
# Fallback DNS Server (werden durch Skript überschrieben)
forward-addr: 8.8.8.8
forward-addr: 8.8.4.4
forward-addr: 1.1.1.1
forward-addr: 1.0.0.1
forward-addr: 163.116.178.73
forward-addr: 163.116.178.74
EOF
# ===== DYNAMISCHE DNS-KONFIGURATION =====
progress "Erstelle dynamisches DNS-Konfigurationsskript..."
cat > "/usr/local/bin/configure-dns-priority" << 'EOF'
#!/bin/bash
# Dynamische DNS-Konfiguration mit Router-Priorität
# Automatische Erkennung und Konfiguration der besten DNS-Server
LOG_FILE="/var/log/dns-configuration.log"
UNBOUND_CONF="/etc/unbound/unbound.conf"
RESOLV_CONF="/etc/resolv.conf"
log_dns() {
echo "$(date): $1" >> "$LOG_FILE"
}
# Erkenne Router-DNS
get_router_dns() {
local router_dns=""
# Methode 1: DHCP Lease-Datei
if [ -f "/var/lib/dhcp/dhclient.leases" ]; then
router_dns=$(grep "domain-name-servers" /var/lib/dhcp/dhclient.leases | tail -1 | cut -d' ' -f3- | tr -d ';' | tr ',' ' ')
fi
# Methode 2: systemd-resolved
if [ -z "$router_dns" ] && command -v systemd-resolve &> /dev/null; then
router_dns=$(systemd-resolve --status | grep "DNS Servers" | head -1 | cut -d: -f2 | xargs)
fi
# Methode 3: NetworkManager
if [ -z "$router_dns" ] && command -v nmcli &> /dev/null; then
router_dns=$(nmcli dev show | grep "IP4.DNS" | head -1 | cut -d: -f2 | xargs)
fi
# Methode 4: Route-basierte Erkennung
if [ -z "$router_dns" ]; then
local gateway=$(ip route | grep default | head -1 | awk '{print $3}')
if [ -n "$gateway" ]; then
# Versuche Gateway als DNS
if nslookup google.com "$gateway" &> /dev/null; then
router_dns="$gateway"
fi
fi
fi
echo "$router_dns"
}
# Teste DNS-Server
test_dns_server() {
local dns_server="$1"
local timeout=3
if [ -z "$dns_server" ]; then
return 1
fi
# Teste mit nslookup
if timeout "$timeout" nslookup google.com "$dns_server" &> /dev/null; then
return 0
fi
# Teste mit dig (falls verfügbar)
if command -v dig &> /dev/null; then
if timeout "$timeout" dig @"$dns_server" google.com &> /dev/null; then
return 0
fi
fi
return 1
}
# Konfiguriere Unbound mit priorisierten DNS-Servern
configure_unbound() {
local router_dns="$1"
local config_section=""
log_dns "Konfiguriere Unbound mit Router-DNS: $router_dns"
# Erstelle Forward-Zone-Konfiguration
config_section="forward-zone:\n name: \".\"\n"
# 1. Priorität: Router DNS (falls verfügbar und funktional)
if [ -n "$router_dns" ]; then
for dns in $router_dns; do
if test_dns_server "$dns"; then
config_section="${config_section} forward-addr: $dns\n"
log_dns "Router DNS hinzugefügt: $dns"
else
log_dns "Router DNS nicht erreichbar: $dns"
fi
done
fi
# 2. Priorität: Google DNS
config_section="${config_section} forward-addr: 8.8.8.8\n"
config_section="${config_section} forward-addr: 8.8.4.4\n"
# 3. Priorität: Cloudflare DNS
config_section="${config_section} forward-addr: 1.1.1.1\n"
config_section="${config_section} forward-addr: 1.0.0.1\n"
# 4. Priorität: Custom DNS Server
config_section="${config_section} forward-addr: 163.116.178.73\n"
config_section="${config_section} forward-addr: 163.116.178.74\n"
# Ersetze Forward-Zone in Unbound-Konfiguration
sed -i '/^forward-zone:/,$d' "$UNBOUND_CONF"
echo -e "$config_section" >> "$UNBOUND_CONF"
# Unbound neu laden
systemctl reload unbound || systemctl restart unbound
log_dns "Unbound-Konfiguration aktualisiert und neu geladen"
}
# Konfiguriere /etc/resolv.conf
configure_resolv_conf() {
log_dns "Konfiguriere /etc/resolv.conf für lokalen Unbound"
# Backup erstellen
cp "$RESOLV_CONF" "${RESOLV_CONF}.backup" 2>/dev/null || true
# Neue resolv.conf erstellen
cat > "$RESOLV_CONF" << 'RESOLV_EOF'
# MYP Kiosk DNS-Konfiguration
# Lokaler Unbound DNS Resolver mit intelligenten Fallbacks
nameserver 127.0.0.1
# Fallback DNS Server (falls Unbound nicht verfügbar)
nameserver 8.8.8.8
nameserver 8.8.4.4
# Suchdomänen
search local
# Optionen
options timeout:2
options attempts:3
options rotate
RESOLV_EOF
# Schreibschutz setzen (verhindert Überschreibung durch DHCP)
chattr +i "$RESOLV_CONF" 2>/dev/null || true
log_dns "/etc/resolv.conf konfiguriert und geschützt"
}
# Hauptfunktion
main() {
log_dns "=== DNS-Konfiguration gestartet ==="
# Router-DNS ermitteln
router_dns=$(get_router_dns)
log_dns "Erkannte Router-DNS: ${router_dns:-'Keine gefunden'}"
# Unbound konfigurieren
configure_unbound "$router_dns"
# resolv.conf konfigurieren
configure_resolv_conf
# DNS-Test
if nslookup google.com 127.0.0.1 &> /dev/null; then
log_dns "✅ DNS-Konfiguration erfolgreich - Test bestanden"
else
log_dns "⚠️ DNS-Test fehlgeschlagen - Fallback aktiv"
fi
log_dns "=== DNS-Konfiguration abgeschlossen ==="
}
# Skript ausführen
main "$@"
EOF
chmod +x /usr/local/bin/configure-dns-priority
# ===== SYSTEMD-SERVICE FÜR DNS-KONFIGURATION =====
progress "Erstelle systemd-Service für DNS-Konfiguration..."
cat > "/etc/systemd/system/dns-priority-config.service" << 'EOF'
[Unit]
Description=Configure DNS Priority with Router Detection
After=network-online.target unbound.service
Wants=network-online.target
Before=myp-druckerverwaltung.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/configure-dns-priority
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
systemctl enable dns-priority-config.service
# ===== DHCP-CLIENT KONFIGURATION =====
progress "Konfiguriere DHCP-Client für DNS-Schutz..."
# dhclient-Konfiguration (verhindert DNS-Überschreibung)
if [ -f "/etc/dhcp/dhclient.conf" ]; then
# Backup erstellen
cp /etc/dhcp/dhclient.conf /etc/dhcp/dhclient.conf.backup
# DNS-Überschreibung verhindern
if ! grep -q "supersede domain-name-servers" /etc/dhcp/dhclient.conf; then
echo "" >> /etc/dhcp/dhclient.conf
echo "# MYP Kiosk: Verhindere DNS-Überschreibung durch DHCP" >> /etc/dhcp/dhclient.conf
echo "supersede domain-name-servers 127.0.0.1;" >> /etc/dhcp/dhclient.conf
fi
fi
# NetworkManager-Konfiguration (falls vorhanden)
if [ -d "/etc/NetworkManager/conf.d" ]; then
cat > "/etc/NetworkManager/conf.d/dns-priority.conf" << 'EOF'
[main]
dns=none
[connection]
ipv6.method=ignore
EOF
info "NetworkManager DNS-Überschreibung deaktiviert"
fi
# ===== UNBOUND STARTEN UND KONFIGURIEREN =====
progress "Starte und konfiguriere Unbound..."
# Root Hints herunterladen
curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache 2>/dev/null || \
wget -O /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache 2>/dev/null || \
warning "Root Hints Download fehlgeschlagen"
# Unbound-Benutzer Berechtigungen
# Prüfe ob unbound-Benutzer existiert, sonst erstelle ihn oder verwende root
if ! id "unbound" &>/dev/null; then
warning "unbound-Benutzer nicht gefunden - versuche Erstellung..."
if ! useradd --system --no-create-home --shell /bin/false unbound 2>/dev/null; then
warning "unbound-Benutzer konnte nicht erstellt werden - verwende root"
chown -R root:root /var/lib/unbound 2>/dev/null || true
chown root:root /etc/unbound/unbound.conf 2>/dev/null || true
else
chown -R unbound:unbound /var/lib/unbound 2>/dev/null || true
chown unbound:unbound /etc/unbound/unbound.conf 2>/dev/null || true
fi
else
chown -R unbound:unbound /var/lib/unbound 2>/dev/null || true
chown unbound:unbound /etc/unbound/unbound.conf 2>/dev/null || true
fi
# Unbound aktivieren und starten
systemctl enable unbound
systemctl start unbound
# DNS-Konfiguration ausführen
/usr/local/bin/configure-dns-priority
# ===== CRON-JOB FÜR REGELMÄSSIGE DNS-UPDATES =====
progress "Konfiguriere automatische DNS-Updates..."
cat > "/etc/cron.d/dns-priority-update" << 'EOF'
# DNS-Priorität alle 30 Minuten aktualisieren
*/30 * * * * root /usr/local/bin/configure-dns-priority >/dev/null 2>&1
# Root Hints wöchentlich aktualisieren
0 3 * * 0 root curl -s -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache && systemctl reload unbound
EOF
# ===== DNS-MONITORING SKRIPT =====
progress "Erstelle DNS-Monitoring..."
cat > "/usr/local/bin/dns-health-check" << 'EOF'
#!/bin/bash
# DNS-Gesundheitscheck für MYP Kiosk
LOG_FILE="/var/log/dns-health.log"
log_health() {
echo "$(date): $1" >> "$LOG_FILE"
}
# Teste DNS-Auflösung
test_dns_resolution() {
local test_domains=("google.com" "github.com" "debian.org")
local failed_count=0
for domain in "${test_domains[@]}"; do
if ! nslookup "$domain" 127.0.0.1 &> /dev/null; then
((failed_count++))
log_health "DNS-Auflösung fehlgeschlagen für: $domain"
fi
done
if [ $failed_count -eq 0 ]; then
log_health "✅ DNS-Gesundheitscheck bestanden"
return 0
elif [ $failed_count -lt ${#test_domains[@]} ]; then
log_health "⚠️ DNS-Gesundheitscheck teilweise fehlgeschlagen ($failed_count/${#test_domains[@]})"
return 1
else
log_health "❌ DNS-Gesundheitscheck komplett fehlgeschlagen"
return 2
fi
}
# Unbound-Status prüfen
check_unbound_status() {
if systemctl is-active --quiet unbound; then
log_health "✅ Unbound läuft"
return 0
else
log_health "❌ Unbound läuft nicht - versuche Neustart"
systemctl restart unbound
sleep 3
if systemctl is-active --quiet unbound; then
log_health "✅ Unbound erfolgreich neu gestartet"
return 0
else
log_health "❌ Unbound-Neustart fehlgeschlagen"
return 1
fi
fi
}
# Hauptfunktion
main() {
check_unbound_status
test_dns_resolution
local exit_code=$?
# Bei kritischen Fehlern: DNS-Konfiguration neu laden
if [ $exit_code -eq 2 ]; then
log_health "Kritischer DNS-Fehler - lade Konfiguration neu"
/usr/local/bin/configure-dns-priority
fi
return $exit_code
}
main "$@"
EOF
chmod +x /usr/local/bin/dns-health-check
# DNS-Health-Check zu Cron hinzufügen
cat >> "/etc/cron.d/dns-priority-update" << 'EOF'
# DNS-Gesundheitscheck alle 10 Minuten
*/10 * * * * root /usr/local/bin/dns-health-check >/dev/null 2>&1
EOF
log "✅ DNS und Netzwerk-Optimierung abgeschlossen"
}
# ========================== AUTO-LOGIN KONFIGURATION ==========================
configure_autologin() {
log "=== PHASE 6.5: AUTO-LOGIN KONFIGURATION ==="
progress "Installiere und konfiguriere Display Manager..."
# LightDM installieren für besseres Auto-Login-Management
apt-get install -y lightdm lightdm-gtk-greeter || true
# Stoppe andere Display Manager
for dm in gdm gdm3 sddm xdm nodm; do
systemctl stop "$dm" 2>/dev/null || true
systemctl disable "$dm" 2>/dev/null || true
done
progress "Konfiguriere LightDM für Auto-Login..."
# LightDM-Konfiguration für automatischen Login
cat > "/etc/lightdm/lightdm.conf" << EOF
[Seat:*]
# Automatischer Login für Kiosk-Benutzer
autologin-user=$KIOSK_USER
autologin-user-timeout=0
autologin-session=openbox
user-session=openbox
session-wrapper=/etc/X11/Xsession
greeter-session=lightdm-gtk-greeter
allow-guest=false
# Kein Benutzer-Wechsel möglich
greeter-hide-users=true
greeter-show-manual-login=false
# Automatischer Start ohne Verzögerung
autologin-in-background=false
# Session-Setup
session-setup-script=/usr/share/lightdm/setup-kiosk-session.sh
EOF
progress "Erstelle Session-Setup-Skript..."
# Session-Setup-Skript für zusätzliche Sicherheit
cat > "/usr/share/lightdm/setup-kiosk-session.sh" << EOF
#!/bin/bash
# Session-Setup für Kiosk-Modus
# Stelle sicher, dass X11-Display verfügbar ist
export DISPLAY=:0
# Deaktiviere Bildschirmschoner und Power Management
xset s off
xset s noblank
xset s noexpose
xset -dpms
# Verstecke Mauszeiger
unclutter -idle 0.5 -root &
# Logge Session-Start
echo "\$(date): Kiosk-Session für Benutzer $KIOSK_USER gestartet" >> /var/log/kiosk-session.log
EOF
chmod +x "/usr/share/lightdm/setup-kiosk-session.sh"
progress "Konfiguriere Getty Auto-Login als Fallback..."
# Getty Auto-Login als Fallback konfigurieren (falls LightDM fehlschlägt)
mkdir -p "/etc/systemd/system/getty@tty1.service.d"
cat > "/etc/systemd/system/getty@tty1.service.d/autologin.conf" << EOF
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin $KIOSK_USER --noclear %I \$TERM
Type=simple
EOF
progress "Erstelle Desktop-Session für Openbox..."
# Desktop-Session-Datei für Openbox
mkdir -p "/usr/share/xsessions"
cat > "/usr/share/xsessions/openbox.desktop" << EOF
[Desktop Entry]
Name=Openbox
Comment=A lightweight window manager
Exec=openbox-session
Type=XSession
DesktopNames=OPENBOX
EOF
# Kiosk-Benutzer Desktop-Umgebung konfigurieren
progress "Konfiguriere Desktop-Umgebung für Kiosk-Benutzer..."
KIOSK_HOME="/home/$KIOSK_USER"
# .xsessionrc für X-Session-Setup
cat > "$KIOSK_HOME/.xsessionrc" << EOF
#!/bin/bash
# X-Session-Setup für Kiosk-Modus
# Export Display
export DISPLAY=:0
# Starte Session-Log
echo "\$(date): X-Session gestartet für Kiosk-Benutzer" >> /var/log/kiosk-session.log
# Führe Kiosk-Setup aus
exec openbox-session
EOF
# .xinitrc für xinit/startx
cat > "$KIOSK_HOME/.xinitrc" << EOF
#!/bin/bash
# Xinit-Konfiguration für Kiosk-Modus
# Export Display
export DISPLAY=:0
# Session-Setup
xset s off
xset s noblank
xset s noexpose
xset -dpms
# Verstecke Mauszeiger
unclutter -idle 0.5 -root &
# Starte Openbox
exec openbox-session
EOF
# Log-Dateiberechtigungen sind bereits korrekt gesetzt (root:root)
info "Log-Dateiberechtigungen erfolgreich konfiguriert"
fi
EOF
# 3. PROFILE AUTOSTART
progress "Konfiguriere .profile autostart..."
cat >> "$KIOSK_HOME/.profile" << 'EOF'
# ===== KIOSK AUTOSTART (PROFILE) =====
if [ -z "$SSH_CLIENT" ] && [ -z "$SSH_TTY" ] && [ -z "$KIOSK_STARTED" ]; then
export KIOSK_STARTED=1
# Starte X-Session falls nicht vorhanden
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then
echo "Starte X-Session via .profile"
exec startx
fi
fi
EOF
# 4. DESKTOP AUTOSTART
progress "Konfiguriere XDG autostart..."
sudo -u "$KIOSK_USER" mkdir -p "$KIOSK_HOME/.config/autostart"
cat > "$KIOSK_HOME/.config/autostart/kiosk-app.desktop" << EOF
[Desktop Entry]
Type=Application
Name=MYP Kiosk Application
Comment=Startet die MYP Kiosk-Anwendung
Exec=$KIOSK_HOME/start-kiosk.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
StartupNotify=false
EOF
chown "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.config/autostart/kiosk-app.desktop"
# 5. CRON AUTOSTART (ÜBERWACHUNG)
progress "Konfiguriere Cron-Überwachung..."
cat > "/etc/cron.d/kiosk-watchdog" << EOF
# Kiosk-Überwachung: Startet Kiosk neu falls nicht läuft
*/2 * * * * $KIOSK_USER /bin/bash -c 'if ! pgrep -f "chromium.*kiosk" > /dev/null; then echo "\$(date): Kiosk-Watchdog startet Anwendung neu" >> /var/log/kiosk-watchdog.log; DISPLAY=:0 $HOME/start-kiosk.sh & fi'
EOF
# 6. RC.LOCAL FALLBACK
progress "Konfiguriere rc.local Fallback..."
cat > "/etc/rc.local" << EOF
#!/bin/bash
# rc.local - Kiosk-Fallback
# Warte auf System-Initialisierung
sleep 10
# Starte Kiosk-Services falls nicht läuft
if ! systemctl is-active --quiet lightdm; then
systemctl start lightdm
fi
if ! systemctl is-active --quiet myp-druckerverwaltung; then
systemctl start myp-druckerverwaltung
fi
# Logge Start
echo "\$(date): rc.local Kiosk-Fallback ausgeführt" >> /var/log/kiosk-fallback.log
exit 0
EOF
chmod +x "/etc/rc.local"
# 7. SYSTEMD SERVICE ÜBERWACHUNG
progress "Konfiguriere Service-Überwachung..."
cat > "/etc/systemd/system/kiosk-watchdog.service" << EOF
[Unit]
Description=Kiosk Watchdog Service
After=multi-user.target
[Service]
Type=simple
User=root
ExecStart=/bin/bash -c 'while true; do if ! systemctl is-active --quiet myp-kiosk; then systemctl start myp-kiosk; fi; sleep 30; done'
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable kiosk-watchdog.service
# Berechtigungen finalisieren
chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.config"
chown "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.bashrc"
chown "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.profile"
log "✅ Mehrfache Autostart-Absicherung implementiert"
}
# ========================== AUTOSTART KONFIGURATION ==========================
configure_autostart() {
log "=== PHASE 7: AUTOSTART-KONFIGURATION ==="
# Systemd Service für Anwendung
progress "Erstelle Systemd-Service für Anwendung..."
cat > "/etc/systemd/system/myp-druckerverwaltung.service" << EOF
[Unit]
Description=MYP Druckerverwaltung Flask Application
After=network.target
[Service]
Type=simple
User=$APP_USER
Group=$APP_USER
WorkingDirectory=$APP_DIR
Environment=PATH=/usr/local/bin:/usr/bin:/bin
Environment=PYTHONPATH=$APP_DIR
ExecStart=/usr/bin/python3 $APP_DIR/app.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# Systemd Service für LightDM Management (ersetzt den alten X-Server Service)
progress "Erstelle Systemd-Service für Display Manager..."
cat > "/etc/systemd/system/myp-display.service" << EOF
[Unit]
Description=MYP Display Manager Service
After=myp-druckerverwaltung.service network.target
Requires=myp-druckerverwaltung.service
Wants=myp-druckerverwaltung.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/bin/bash -c 'while ! curl -s http://localhost:5000 > /dev/null; do sleep 2; done'
ExecStart=/bin/systemctl start lightdm
ExecStop=/bin/systemctl stop lightdm
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=graphical.target
EOF
# Systemd Service für Kiosk-Überwachung
progress "Erstelle erweiterten Kiosk-Überwachungs-Service..."
cat > "/etc/systemd/system/myp-kiosk-monitor.service" << EOF
[Unit]
Description=MYP Kiosk Monitor und Recovery Service
After=graphical.target lightdm.service
Requires=myp-druckerverwaltung.service
[Service]
Type=simple
User=root
ExecStart=/bin/bash -c '
while true; do
# Prüfe ob Anwendung läuft
if ! curl -s http://localhost:5000 > /dev/null; then
echo "\$(date): Anwendung nicht erreichbar - starte neu" >> /var/log/kiosk-monitor.log
systemctl restart myp-druckerverwaltung
sleep 10
fi
# Prüfe ob LightDM läuft
if ! systemctl is-active --quiet lightdm; then
echo "\$(date): LightDM nicht aktiv - starte neu" >> /var/log/kiosk-monitor.log
systemctl start lightdm
sleep 5
fi
# Prüfe ob Kiosk-Benutzer angemeldet ist
if ! pgrep -u $KIOSK_USER > /dev/null; then
echo "\$(date): Kiosk-Benutzer nicht angemeldet - starte LightDM neu" >> /var/log/kiosk-monitor.log
systemctl restart lightdm
sleep 10
fi
# Prüfe ob Chromium im Kiosk-Modus läuft
if ! pgrep -u $KIOSK_USER -f "chromium.*kiosk" > /dev/null; then
echo "\$(date): Chromium-Kiosk nicht gefunden - starte Kiosk-Session neu" >> /var/log/kiosk-monitor.log
# Versuche Kiosk-Neustart als Kiosk-Benutzer
sudo -u $KIOSK_USER DISPLAY=:0 /home/$KIOSK_USER/start-kiosk.sh &
fi
sleep 30
done
'
Restart=always
RestartSec=10
[Install]
WantedBy=graphical.target
EOF
# Nginx-Proxy-Konfiguration
progress "Konfiguriere Nginx..."
cat > "/etc/nginx/sites-available/myp-kiosk" << EOF
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# Security Headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';" always;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
# WebSocket-Support
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
# Timeout-Konfiguration
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Statische Dateien
location /static/ {
alias $APP_DIR/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# Nginx-Site aktivieren
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/myp-kiosk /etc/nginx/sites-enabled/
# Erstelle systemd-logind Konfiguration für besseres Session-Management
progress "Konfiguriere systemd-logind für Kiosk..."
cat > "/etc/systemd/logind.conf.d/kiosk.conf" << EOF
[Login]
# Verhindere dass System bei Inaktivität heruntergefahren wird
IdleAction=ignore
IdleActionSec=infinity
# Verhindere Suspend/Hibernate
HandlePowerKey=ignore
HandleSuspendKey=ignore
HandleHibernateKey=ignore
HandleLidSwitch=ignore
# Session-Einstellungen für Kiosk
KillUserProcesses=no
UserStopDelaySec=10
# Automatic VT allocation
ReserveVT=1
EOF
# Erstelle PAM-Konfiguration für Auto-Login
progress "Konfiguriere PAM für Auto-Login..."
cat > "/etc/pam.d/lightdm-autologin" << EOF
# PAM configuration for LightDM autologin
auth required pam_env.so
auth required pam_permit.so
@include common-account
session required pam_limits.so
@include common-session
@include common-password
EOF
# Services aktivieren
progress "Aktiviere Services..."
systemctl daemon-reload
systemctl enable myp-druckerverwaltung
systemctl enable nginx
systemctl enable myp-display
systemctl enable myp-kiosk-monitor
# SSH standardmäßig deaktivieren für Sicherheit
systemctl disable ssh || true
# Sicherstellen dass graphical.target Standard ist
systemctl set-default graphical.target
# Erstelle systemd override für bessere Kiosk-Integration
progress "Erstelle systemd-Overrides..."
mkdir -p "/etc/systemd/system/lightdm.service.d"
cat > "/etc/systemd/system/lightdm.service.d/kiosk-override.conf" << EOF
[Unit]
After=myp-druckerverwaltung.service
[Service]
# Automatischer Restart bei Fehlern
Restart=always
RestartSec=5
# Umgebungsvariablen für Kiosk
Environment=DISPLAY=:0
Environment=KIOSK_MODE=1
EOF
log "✅ Autostart konfiguriert mit LightDM-Integration"
}
# ========================== SICHERHEIT ==========================
configure_security() {
log "=== PHASE 8: SICHERHEITS-KONFIGURATION ==="
progress "Konfiguriere Firewall..."
ufw --force enable
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
progress "Konfiguriere Fail2Ban..."
cat > "/etc/fail2ban/jail.local" << EOF
[DEFAULT]
bantime = 600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
EOF
# Automatische Updates
progress "Konfiguriere automatische Updates..."
apt-get install -y unattended-upgrades
echo 'Unattended-Upgrade::Automatic-Reboot "false";' > /etc/apt/apt.conf.d/50unattended-upgrades-local
# Kiosk-Benutzer Einschränkungen
progress "Beschränke Kiosk-Benutzer..."
# Kein sudo für kiosk-Benutzer
gpasswd -d "$KIOSK_USER" sudo 2>/dev/null || true
# Shell auf /bin/false für bessere Sicherheit (aber X11 muss funktionieren)
# usermod -s /bin/false "$KIOSK_USER" # Erstmal nicht, da X11 funktionieren muss
log "✅ Sicherheit konfiguriert"
}
# ========================== WARTUNGSTOOLS ==========================
create_maintenance_tools() {
log "=== PHASE 9: WARTUNGSTOOLS ==="
# Wartungsskript
cat > "/usr/local/bin/myp-maintenance" << 'EOF'
#!/bin/bash
case "$1" in
start)
echo "Starte alle MYP-Services..."
systemctl start myp-druckerverwaltung
systemctl start nginx
systemctl start myp-display
systemctl start myp-kiosk-monitor
echo "Services gestartet."
;;
stop)
echo "Stoppe alle MYP-Services..."
systemctl stop myp-kiosk-monitor
systemctl stop myp-display
systemctl stop lightdm
systemctl stop nginx
systemctl stop myp-druckerverwaltung
echo "Services gestoppt."
;;
restart)
echo "Starte alle MYP-Services neu..."
systemctl restart myp-druckerverwaltung
sleep 3
systemctl restart nginx
systemctl restart myp-display
systemctl restart myp-kiosk-monitor
echo "Services neugestartet."
;;
status)
echo "=== MYP SYSTEM STATUS ==="
echo
echo "📱 Anwendung:"
systemctl status myp-druckerverwaltung --no-pager -l
echo
echo "🌐 Nginx Proxy:"
systemctl status nginx --no-pager -l
echo
echo "🖥️ Display Manager:"
systemctl status lightdm --no-pager -l
echo
echo "🔍 Kiosk Monitor:"
systemctl status myp-kiosk-monitor --no-pager -l
echo
echo "👤 Kiosk-Benutzer-Sessions:"
who | grep kiosk || echo "Kein Kiosk-Benutzer angemeldet"
echo
echo "🌐 Anwendung erreichbar:"
if curl -s http://localhost:5000 > /dev/null; then
echo "✅ http://localhost:5000 erreichbar"
else
echo "❌ http://localhost:5000 NICHT erreichbar"
fi
;;
logs)
echo "=== ANWENDUNGS-LOGS (Strg+C zum Beenden) ==="
journalctl -u myp-druckerverwaltung -f
;;
kiosk-logs)
echo "=== KIOSK-LOGS (Strg+C zum Beenden) ==="
echo "Monitor-Logs:"
journalctl -u myp-kiosk-monitor -f &
echo "LightDM-Logs:"
journalctl -u lightdm -f &
echo "Session-Logs:"
tail -f /var/log/kiosk-session.log 2>/dev/null &
wait
;;
app-restart)
echo "Starte nur Anwendung neu..."
systemctl restart myp-druckerverwaltung
echo "Anwendung neugestartet."
;;
kiosk-restart)
echo "Starte nur Kiosk-Display neu..."
systemctl restart lightdm
echo "Kiosk-Display neugestartet."
;;
monitor-restart)
echo "Starte Kiosk-Monitor neu..."
systemctl restart myp-kiosk-monitor
echo "Kiosk-Monitor neugestartet."
;;
enable-ssh)
echo "Aktiviere SSH für Wartung..."
systemctl enable ssh
systemctl start ssh
echo "✅ SSH aktiviert für Remote-Wartung"
echo "SSH-Status: $(systemctl is-active ssh)"
echo "IP-Adresse: $(hostname -I | awk '{print $1}')"
;;
disable-ssh)
echo "Deaktiviere SSH für Sicherheit..."
systemctl stop ssh
systemctl disable ssh
echo "✅ SSH deaktiviert"
;;
exit-kiosk)
echo "🔐 KIOSK-MODUS BEENDEN"
echo "WARNUNG: Stoppt den Kiosk und aktiviert Wartungsmodus!"
echo "Passwort erforderlich für Sicherheit."
read -s -p "Kiosk-Passwort: " password
echo
if [ "$password" = "744563017196A" ]; then
echo "✅ Passwort korrekt - beende Kiosk-Modus..."
systemctl stop myp-kiosk-monitor
systemctl stop lightdm
systemctl enable ssh
systemctl start ssh
echo "🔧 Wartungsmodus aktiviert:"
echo " • Kiosk gestoppt"
echo " • SSH aktiviert"
echo " • Console verfügbar"
echo "Kiosk-Neustart mit: myp-maintenance start"
else
echo "❌ Falsches Passwort! Kiosk bleibt aktiv."
exit 1
fi
;;
enter-kiosk)
echo "Aktiviere Kiosk-Modus..."
systemctl disable ssh 2>/dev/null || true
systemctl stop ssh 2>/dev/null || true
systemctl start myp-druckerverwaltung
systemctl start nginx
systemctl start myp-display
systemctl start myp-kiosk-monitor
echo "✅ Kiosk-Modus aktiviert"
;;
check-health)
echo "=== SYSTEM-GESUNDHEITSCHECK ==="
echo
# Services-Check
echo "📋 Service-Status:"
for service in myp-druckerverwaltung nginx lightdm myp-kiosk-monitor; do
if systemctl is-active --quiet $service; then
echo " ✅ $service: aktiv"
else
echo " ❌ $service: INAKTIV"
fi
done
# DNS-Service-Check
if systemctl is-active --quiet unbound; then
echo " ✅ unbound: aktiv"
else
echo " ❌ unbound: INAKTIV"
fi
echo
# Netzwerk-Check
echo "🌐 Netzwerk-Status:"
if curl -s http://localhost:5000 > /dev/null; then
echo " ✅ Anwendung erreichbar"
else
echo " ❌ Anwendung NICHT erreichbar"
fi
# DNS-Check
if nslookup google.com 127.0.0.1 &> /dev/null; then
echo " ✅ DNS-Auflösung funktional"
else
echo " ❌ DNS-Auflösung FEHLERHAFT"
fi
# IPv6-Check
if [ "$(sysctl -n net.ipv6.conf.all.disable_ipv6)" = "1" ]; then
echo " ✅ IPv6 deaktiviert (gewünscht)"
else
echo " ⚠️ IPv6 noch aktiv"
fi
echo
# Kiosk-Check
echo "🖥️ Kiosk-Status:"
if pgrep -u kiosk > /dev/null; then
echo " ✅ Kiosk-Benutzer angemeldet"
else
echo " ❌ Kiosk-Benutzer NICHT angemeldet"
fi
if pgrep -f "chromium.*kiosk" > /dev/null; then
echo " ✅ Chromium-Kiosk läuft"
else
echo " ❌ Chromium-Kiosk läuft NICHT"
fi
echo
# Ressourcen-Check
echo "💾 System-Ressourcen:"
echo " CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)% belegt"
echo " RAM: $(free | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100.0}')"
echo " Disk: $(df / | tail -1 | awk '{print $5}')"
;;
auto-fix)
echo "🔧 AUTOMATISCHE REPARATUR"
echo "Versuche häufige Probleme zu beheben..."
# Services neu starten
echo "1. Starte Services neu..."
systemctl restart myp-druckerverwaltung
sleep 3
systemctl restart nginx
systemctl restart lightdm
systemctl restart myp-kiosk-monitor
# DNS-Services reparieren
echo "2. Repariere DNS-Services..."
systemctl restart unbound
systemctl restart dns-priority-config
/usr/local/bin/configure-dns-priority
# Berechtigungen reparieren
echo "3. Repariere Berechtigungen..."
chown -R kiosk:kiosk /home/kiosk
chown -R myp:myp /opt/myp-druckerverwaltung
# Logs bereinigen
echo "4. Bereinige alte Logs..."
journalctl --rotate
journalctl --vacuum-time=7d
echo "✅ Automatische Reparatur abgeschlossen"
echo "Prüfe Status mit: myp-maintenance check-health"
;;
dns-status)
echo "=== DNS-KONFIGURATION STATUS ==="
echo
echo "🔍 Unbound Service:"
systemctl status unbound --no-pager -l
echo
echo "📋 Aktuelle DNS-Server:"
cat /etc/resolv.conf | grep nameserver
echo
echo "🌐 Router-DNS (erkannt):"
/usr/local/bin/configure-dns-priority 2>/dev/null | grep "Erkannte Router-DNS" | tail -1 || echo "Keine Router-DNS erkannt"
echo
echo "📊 DNS-Statistiken:"
if command -v unbound-control &> /dev/null; then
unbound-control stats_noreset 2>/dev/null | head -10 || echo "Unbound-Control nicht verfügbar"
fi
echo
echo "📝 Letzte DNS-Logs:"
tail -10 /var/log/dns-configuration.log 2>/dev/null || echo "Keine DNS-Logs verfügbar"
;;
dns-test)
echo "=== DNS-AUFLÖSUNGSTEST ==="
echo
test_domains=("google.com" "github.com" "debian.org" "cloudflare.com")
for domain in "${test_domains[@]}"; do
echo -n "Testing $domain: "
if nslookup "$domain" 127.0.0.1 &> /dev/null; then
echo "✅ OK"
else
echo "❌ FEHLER"
fi
done
echo
echo "🔍 DNS-Gesundheitscheck:"
/usr/local/bin/dns-health-check
;;
dns-reconfigure)
echo "=== DNS-KONFIGURATION NEU LADEN ==="
echo "Lade DNS-Konfiguration mit Router-Erkennung neu..."
/usr/local/bin/configure-dns-priority
echo "✅ DNS-Konfiguration neu geladen"
echo "Test mit: myp-maintenance dns-test"
;;
ipv6-status)
echo "=== IPv6-STATUS ==="
echo
echo "🔍 IPv6 Kernel-Parameter:"
sysctl net.ipv6.conf.all.disable_ipv6
sysctl net.ipv6.conf.default.disable_ipv6
echo
echo "🌐 IPv6-Adressen:"
ip -6 addr show | grep inet6 || echo "Keine IPv6-Adressen (deaktiviert)"
echo
echo "📋 IPv6-Routen:"
ip -6 route show 2>/dev/null || echo "Keine IPv6-Routen (deaktiviert)"
;;
*)
echo "MYP Druckerverwaltung - Wartungstool"
echo
echo "VERWENDUNG: $0 BEFEHL"
echo
echo "SERVICE-MANAGEMENT:"
echo " start Alle Services starten"
echo " stop Alle Services stoppen"
echo " restart Alle Services neustarten"
echo " status Detaillierter Status aller Services"
echo
echo "EINZELNE SERVICES:"
echo " app-restart Nur Anwendung neustarten"
echo " kiosk-restart Nur Kiosk-Display neustarten"
echo " monitor-restart Nur Kiosk-Monitor neustarten"
echo
echo "LOGS & MONITORING:"
echo " logs Live Anwendungs-Logs anzeigen"
echo " kiosk-logs Live Kiosk-Logs anzeigen"
echo " check-health System-Gesundheitscheck"
echo
echo "KIOSK-KONTROLLE:"
echo " exit-kiosk Kiosk beenden (Passwort: 744563017196A)"
echo " enter-kiosk Kiosk-Modus aktivieren"
echo
echo "DNS & NETZWERK:"
echo " dns-status DNS-Konfiguration anzeigen"
echo " dns-test DNS-Auflösung testen"
echo " dns-reconfigure DNS-Konfiguration neu laden"
echo " ipv6-status IPv6-Status prüfen"
echo
echo "WARTUNG:"
echo " enable-ssh SSH für Remote-Wartung aktivieren"
echo " disable-ssh SSH wieder deaktivieren"
echo " auto-fix Automatische Problemreparatur"
echo
echo "BEISPIELE:"
echo " $0 status # System-Status anzeigen"
echo " $0 logs # Live-Logs verfolgen"
echo " $0 exit-kiosk # Wartungsmodus aktivieren"
;;
esac
EOF
chmod +x /usr/local/bin/myp-maintenance
# Backup-Skript
cat > "/usr/local/bin/myp-backup" << EOF
#!/bin/bash
BACKUP_DIR="$BACKUP_DIR"
DATE=\$(date +%Y%m%d_%H%M%S)
mkdir -p "\$BACKUP_DIR"
echo "Erstelle MYP-System-Backup..."
# Services kurz stoppen für konsistentes Backup
systemctl stop myp-druckerverwaltung
# Erstelle Backup
tar -czf "\$BACKUP_DIR/myp_backup_\$DATE.tar.gz" \\
-C "$APP_DIR" \\
--exclude='node_modules' \\
--exclude='__pycache__' \\
--exclude='venv' \\
--exclude='*.log' \\
database.db .env uploads/ config/ 2>/dev/null || true
# Backup der Kiosk-Konfiguration
tar -czf "\$BACKUP_DIR/kiosk_config_\$DATE.tar.gz" \\
/home/kiosk/.config \\
/etc/lightdm/lightdm.conf \\
/usr/share/lightdm/setup-kiosk-session.sh \\
/etc/systemd/system/myp-*.service \\
/usr/local/bin/myp-* 2>/dev/null || true
# Services wieder starten
systemctl start myp-druckerverwaltung
echo "✅ Backup erstellt:"
echo " Anwendung: \$BACKUP_DIR/myp_backup_\$DATE.tar.gz"
echo " Kiosk-Config: \$BACKUP_DIR/kiosk_config_\$DATE.tar.gz"
# Alte Backups löschen (älter als 30 Tage)
find "\$BACKUP_DIR" -name "myp_backup_*.tar.gz" -mtime +30 -delete 2>/dev/null || true
find "\$BACKUP_DIR" -name "kiosk_config_*.tar.gz" -mtime +30 -delete 2>/dev/null || true
echo "🧹 Alte Backups (>30 Tage) entfernt"
EOF
chmod +x /usr/local/bin/myp-backup
# Notfall-Reset
cat > "/usr/local/bin/myp-emergency-reset" << 'EOF'
#!/bin/bash
echo "🚨 NOTFALL-RESET für MYP Kiosk-System"
echo "======================================"
echo
echo "WARNUNG: Dieser Befehl wird:"
echo " • Alle Kiosk-Services stoppen"
echo " • SSH für Remote-Wartung aktivieren"
echo " • Console-Zugang ermöglichen"
echo " • System in Wartungsmodus versetzen"
echo
echo "Nur bei kritischen Problemen verwenden!"
echo
read -p "Notfall-Reset durchführen? (RESET eingeben): " confirm
if [ "$confirm" = "RESET" ]; then
echo
echo "🔧 Führe Notfall-Reset durch..."
# Stoppe alle Kiosk-Services
systemctl stop myp-kiosk-monitor 2>/dev/null || true
systemctl stop lightdm 2>/dev/null || true
# Aktiviere SSH
systemctl enable ssh 2>/dev/null || true
systemctl start ssh 2>/dev/null || true
# Logge Reset
echo "$(date): Notfall-Reset durchgeführt" >> /var/log/emergency-reset.log
echo "✅ Notfall-Reset abgeschlossen!"
echo
echo "📋 AKTUELLE SITUATION:"
echo " • Kiosk-Modus: GESTOPPT"
echo " • SSH: AKTIVIERT für Remote-Wartung"
echo " • Console: Verfügbar auf TTY1-6 (Strg+Alt+F1-F6)"
echo " • IP-Adresse: $(hostname -I | awk '{print $1}')"
echo
echo "🔧 WARTUNGSOPTIONEN:"
echo " • Status prüfen: myp-maintenance status"
echo " • Gesundheitscheck: myp-maintenance check-health"
echo " • Automatische Fix: myp-maintenance auto-fix"
echo " • Kiosk reaktivieren: myp-maintenance enter-kiosk"
echo
else
echo "❌ Abgebrochen. System bleibt unverändert."
fi
EOF
chmod +x /usr/local/bin/myp-emergency-reset
# Erweiterte Cron-Jobs
cat > "/etc/cron.d/myp-system" << EOF
# MYP System Maintenance Cron Jobs
# Tägliches Backup um 2:00 Uhr
0 2 * * * root /usr/local/bin/myp-backup >> /var/log/myp-backup.log 2>&1
# Gesundheitscheck alle 10 Minuten
*/10 * * * * root /usr/local/bin/myp-maintenance check-health > /dev/null 2>&1 || echo "\$(date): Health check failed" >> /var/log/myp-health.log
# Log-Rotation wöchentlich (Sonntags um 3:00)
0 3 * * 0 root journalctl --rotate && journalctl --vacuum-time=30d
# System-Ressourcen-Log alle 5 Minuten
*/5 * * * * root echo "\$(date),\$(cat /proc/loadavg | cut -d' ' -f1-3),\$(free | grep Mem | awk '{printf \"%.1f\", \$3/\$2 * 100.0}')" >> /var/log/system-resources.log
EOF
log "✅ Erweiterte Wartungstools erstellt"
}
# ========================== FINALE KONFIGURATION ==========================
finalize_installation() {
log "=== PHASE 10: FINALISIERUNG ==="
# Services starten
progress "Starte Services..."
systemctl start myp-druckerverwaltung
sleep 3
systemctl start nginx
# Warte und prüfe Services
sleep 5
if systemctl is-active --quiet myp-druckerverwaltung; then
log "✅ MYP-Anwendung läuft"
else
warning "⚠️ MYP-Anwendung nicht aktiv"
fi
if systemctl is-active --quiet nginx; then
log "✅ Nginx läuft"
else
warning "⚠️ Nginx nicht aktiv"
fi
# Test ob Anwendung erreichbar ist
progress "Teste Anwendung..."
for i in {1..30}; do
if curl -s http://localhost:5000 > /dev/null; then
log "✅ Anwendung erreichbar unter http://localhost:5000"
break
else
if [ $i -eq 30 ]; then
warning "⚠️ Anwendung nach 30 Versuchen nicht erreichbar"
else
sleep 2
fi
fi
done
# Chromium-Test
progress "Teste Chromium-Installation..."
if [[ "$CHROMIUM_BIN" == "flatpak"* ]]; then
sudo -u "$KIOSK_USER" flatpak run org.chromium.Chromium --version > /dev/null 2>&1 && log "✅ Chromium (Flatpak) funktional" || warning "⚠️ Chromium (Flatpak) Test fehlgeschlagen"
else
sudo -u "$KIOSK_USER" "$CHROMIUM_BIN" --version > /dev/null 2>&1 && log "✅ Chromium funktional" || warning "⚠️ Chromium-Test fehlgeschlagen"
fi
# Teste Auto-Login-Konfiguration
progress "Teste Auto-Login-Konfiguration..."
if [ -f "/etc/lightdm/lightdm.conf" ] && grep -q "autologin-user=$KIOSK_USER" "/etc/lightdm/lightdm.conf"; then
log "✅ Auto-Login für $KIOSK_USER konfiguriert"
else
warning "⚠️ Auto-Login-Konfiguration unvollständig"
fi
# Teste Systemd-Services
progress "Teste Service-Konfiguration..."
for service in myp-druckerverwaltung myp-display myp-kiosk-monitor; do
if systemctl is-enabled --quiet "$service" 2>/dev/null; then
log "✅ Service $service aktiviert"
else
warning "⚠️ Service $service nicht aktiviert"
fi
done
# Teste Wartungstools
progress "Teste Wartungstools..."
if [ -x "/usr/local/bin/myp-maintenance" ]; then
log "✅ myp-maintenance verfügbar"
else
warning "⚠️ myp-maintenance nicht verfügbar"
fi
if [ -x "/usr/local/bin/myp-backup" ]; then
log "✅ myp-backup verfügbar"
else
warning "⚠️ myp-backup nicht verfügbar"
fi
if [ -x "/usr/local/bin/myp-emergency-reset" ]; then
log "✅ myp-emergency-reset verfügbar"
else
warning "⚠️ myp-emergency-reset nicht verfügbar"
fi
# Erstelle erste Logs
progress "Initialisiere Logging..."
touch /var/log/kiosk-session.log
touch /var/log/kiosk-monitor.log
touch /var/log/kiosk-watchdog.log
touch /var/log/emergency-reset.log
touch /var/log/myp-backup.log
touch /var/log/myp-health.log
touch /var/log/system-resources.log
# Setze einfache root:root Berechtigungen für alle Log-Dateien (maximale Kompatibilität)
progress "Setze Log-Dateiberechtigungen..."
chown root:root /var/log/kiosk-session.log 2>/dev/null || true
chown root:root /var/log/kiosk-monitor.log 2>/dev/null || true
chown root:root /var/log/kiosk-watchdog.log 2>/dev/null || true
chown root:root /var/log/emergency-reset.log 2>/dev/null || true
chown root:root /var/log/myp-backup.log 2>/dev/null || true
chown root:root /var/log/myp-health.log 2>/dev/null || true
chown root:root /var/log/system-resources.log 2>/dev/null || true
# Setze Lese-/Schreibberechtigungen
chmod 644 /var/log/kiosk-session.log 2>/dev/null || true
chmod 644 /var/log/kiosk-monitor.log 2>/dev/null || true
chmod 644 /var/log/kiosk-watchdog.log 2>/dev/null || true
chmod 644 /var/log/emergency-reset.log 2>/dev/null || true
chmod 644 /var/log/myp-backup.log 2>/dev/null || true
chmod 644 /var/log/myp-health.log 2>/dev/null || true
chmod 644 /var/log/system-resources.log 2>/dev/null || true
# Log-Dateiberechtigungen sind bereits korrekt gesetzt (root:root)
info "Log-Dateiberechtigungen erfolgreich konfiguriert"
# Finale Berechtigungen
chown -R "$APP_USER:$APP_USER" "$APP_DIR"
chown -R "$KIOSK_USER:$KIOSK_USER" "/home/$KIOSK_USER"
# System-Target finalisieren
systemctl set-default graphical.target
log "✅ Installation finalisiert"
}
# ========================== INSTALLATIONS-BERICHT ==========================
show_installation_report() {
local ip_address=$(hostname -I | awk '{print $1}')
cat << EOF
╔══════════════════════════════════════════════════════════════╗
║ 🎉 KIOSK-INSTALLATION ERFOLGREICH! 🎉 ║
╚══════════════════════════════════════════════════════════════╝
📋 INSTALLATIONS-ZUSAMMENFASSUNG:
• System-Typ: Vollautomatischer Sicherheits-Kiosk
• Anwendung: $APP_DIR
• Kiosk-URL: http://$ip_address (nach Neustart)
• Chromium: $CHROMIUM_BIN
• Display Manager: LightDM mit Auto-Login
• Kiosk-Benutzer: $KIOSK_USER (automatisch angemeldet)
• App-Benutzer: $APP_USER
🛡️ SICHERHEITS-FEATURES:
• Desktop-Flucht: Vollständig verhindert
• Tastatur-Shortcuts: Alle deaktiviert
• Browser-Escape: Unmöglich (Kiosk-Flags)
• SSH: Standardmäßig deaktiviert
• Firewall: Aktiv mit Fail2Ban-Schutz
• Auto-Login: Sicher konfiguriert
• Session-Isolation: Kiosk-Benutzer ohne sudo
• IPv6: Systemweit deaktiviert
• DNS: Lokaler Unbound-Resolver mit Router-Priorität
🔧 AUTOSTART-ABSICHERUNG (7-fach):
✅ 1. LightDM Auto-Login
✅ 2. Systemd User-Service
✅ 3. Bashrc Autostart
✅ 4. Profile Autostart
✅ 5. XDG Desktop Autostart
✅ 6. Cron Watchdog
✅ 7. RC.Local Fallback
🚀 SYSTEMD-SERVICES:
• myp-druckerverwaltung.service → Flask-Anwendung
• myp-display.service → LightDM-Management
• myp-kiosk-monitor.service → Kiosk-Überwachung + Recovery
• nginx.service → Reverse-Proxy
• lightdm.service → Display Manager mit Auto-Login
• unbound.service → Lokaler DNS-Resolver
• dns-priority-config.service → Intelligente DNS-Konfiguration
🌐 DNS & NETZWERK-FEATURES:
✅ Router-DNS automatisch erkannt und priorisiert
✅ Fallback-DNS: Google → Cloudflare → Custom
✅ IPv6 systemweit deaktiviert
✅ DHCP-DNS-Überschreibung verhindert
✅ Unbound lokaler Resolver mit DNSSEC
✅ Automatische DNS-Updates alle 30 Min
✅ DNS-Gesundheitscheck alle 10 Min
✅ Intelligente Router-Erkennung (4 Methoden)
🔧 WARTUNGSTOOLS:
📱 myp-maintenance:
• status - Detaillierter System-Status
• restart - Alle Services neustarten
• exit-kiosk - Wartungsmodus (Passwort: 744563017196A)
• enable-ssh - SSH für Remote-Wartung
• check-health - Automatischer Gesundheitscheck
• auto-fix - Automatische Problemreparatur
• dns-status - DNS-Konfiguration anzeigen
• dns-test - DNS-Auflösung testen
• dns-reconfigure - DNS-Konfiguration neu laden
• ipv6-status - IPv6-Status prüfen
💾 myp-backup:
• Automatisch: Täglich 2:00 Uhr
• Manuell: myp-backup
• Aufbewahrung: 30 Tage
🚨 myp-emergency-reset:
• Notfall-Tool bei kritischen Problemen
• Stoppt Kiosk, aktiviert SSH
📊 MONITORING & LOGS:
• System-Health: Alle 10 Minuten automatisch
• Resource-Logs: Alle 5 Minuten
• Service-Überwachung: Kontinuierlich mit Auto-Recovery
• Log-Rotation: Wöchentlich (30 Tage Aufbewahrung)
⚠️ WICHTIGE HINWEISE:
• System bootet automatisch in VOLLBILD-KIOSK ohne Escape
• Kein Desktop verfügbar - nur MYP-Anwendung sichtbar
• SSH deaktiviert für maximale Sicherheit
• Bei Problemen: Console-Zugang via Strg+Alt+F1-F6
🔐 NOTFALL-ZUGANG:
1. Console: Strg+Alt+F1 bis F6 → Login als Root/sudo-User
2. Emergency: myp-emergency-reset → RESET eingeben
3. Remote: myp-maintenance enable-ssh → SSH verfügbar
🚀 NÄCHSTE SCHRITTE:
1. System neustarten: sudo reboot
2. ⏱️ System bootet in ~2 Minuten automatisch in Kiosk-Modus
3. 🖥️ Chromium startet automatisch im Vollbild
4. 📱 MYP-Anwendung verfügbar unter http://$ip_address
5. 🔒 Kein Escape möglich - echtes Kiosk-System
📞 WARTUNG & SUPPORT:
• Live Status: myp-maintenance status
• Logs verfolgen: myp-maintenance logs
• Kiosk beenden: myp-maintenance exit-kiosk
• Gesundheitscheck: myp-maintenance check-health
• Backup erstellen: myp-backup
🎯 LEISTUNGS-FEATURES:
✅ Multi-Browser-Fallback (APT → Snap → Flatpak)
✅ Service-Recovery bei Fehlern
✅ Session-Monitoring mit Auto-Restart
✅ Resource-Monitoring und Logging
✅ Automatische Backups mit Rotation
✅ Health-Checks mit Auto-Fix
✅ Emergency-Recovery-System
══════════════════════════════════════════════════════════════
Installation abgeschlossen: $(date)
Installationslog: $INSTALL_LOG
SYSTEM BEREIT FÜR PRODUKTIONS-KIOSK-BETRIEB! 🚀
══════════════════════════════════════════════════════════════
EOF
}
# ========================== KEYMAP-PROBLEM BEHEBEN ==========================
fix_keymap_issues() {
log "=== PHASE 0.3: KEYMAP-PROBLEME BEHEBEN ==="
progress "Behebe bekannte Keymap-Probleme..."
# Installiere alle keyboard-bezogenen Pakete
progress "Installiere vollständige Keyboard-Unterstützung..."
apt-get install -y \
keyboard-configuration \
console-setup \
console-data \
kbd \
console-common \
xkb-data \
locales \
2>/dev/null || warning "Einige Keyboard-Pakete konnten nicht installiert werden"
# Generiere Locales falls noch nicht vorhanden
progress "Generiere deutsche Locales..."
if [ -f "/etc/locale.gen" ]; then
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen
sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
locale-gen 2>/dev/null || warning "Locale-Generierung teilweise fehlgeschlagen"
update-locale LANG=de_DE.UTF-8 2>/dev/null || true
fi
# Prüfe und repariere Keymap-Verzeichnisse
progress "Prüfe Keymap-Verzeichnisse..."
# Erstelle Keymap-Verzeichnisse falls sie fehlen
mkdir -p /usr/share/keymaps/i386/qwertz 2>/dev/null || true
mkdir -p /usr/share/kbd/keymaps/i386/qwertz 2>/dev/null || true
mkdir -p /lib/kbd/keymaps/i386/qwertz 2>/dev/null || true
# Prüfe ob deutsche Keymap verfügbar ist
KEYMAP_FOUND=false
for keymap_path in \
"/usr/share/keymaps/i386/qwertz/de.kmap.gz" \
"/usr/share/kbd/keymaps/i386/qwertz/de.map.gz" \
"/lib/kbd/keymaps/i386/qwertz/de.map.gz" \
"/usr/share/keymaps/i386/qwertz/de-latin1.kmap.gz" \
"/usr/share/kbd/keymaps/i386/qwertz/de-latin1.map.gz"; do
if [ -f "$keymap_path" ]; then
KEYMAP_FOUND=true
info "Deutsche Keymap gefunden: $keymap_path"
break
fi
done
if [ "$KEYMAP_FOUND" = false ]; then
warning "Keine deutsche Keymap gefunden - versuche Reparatur..."
# Versuche console-data zu rekonfigurieren
if dpkg -l | grep -q console-data; then
dpkg-reconfigure -f noninteractive console-data 2>/dev/null || true
fi
# Versuche kbd zu rekonfigurieren
if dpkg -l | grep -q "^ii.*kbd"; then
dpkg-reconfigure -f noninteractive kbd 2>/dev/null || true
fi
# Fallback: Erstelle minimale deutsche Keymap
if [ ! -f "/usr/share/keymaps/i386/qwertz/de.kmap.gz" ]; then
warning "Erstelle Fallback-Keymap..."
mkdir -p /usr/share/keymaps/i386/qwertz
# Erstelle einfache deutsche Keymap
cat > /tmp/de.kmap << 'EOF'
# German keyboard layout
keymaps 0-15
keycode 1 = Escape
keycode 2 = one exclam
keycode 3 = two quotedbl
keycode 4 = three section
keycode 5 = four dollar
keycode 6 = five percent
keycode 7 = six ampersand
keycode 8 = seven slash
keycode 9 = eight parenleft
keycode 10 = nine parenright
keycode 11 = zero equal
keycode 12 = ssharp question
keycode 13 = dead_acute dead_grave
keycode 14 = BackSpace
keycode 15 = Tab
keycode 16 = q Q
keycode 17 = w W
keycode 18 = e E
keycode 19 = r R
keycode 20 = t T
keycode 21 = z Z
keycode 22 = u U
keycode 23 = i I
keycode 24 = o O
keycode 25 = p P
keycode 26 = udiaeresis Udiaeresis
keycode 27 = plus asterisk
keycode 28 = Return
keycode 29 = Control
keycode 30 = a A
keycode 31 = s S
keycode 32 = d D
keycode 33 = f F
keycode 34 = g G
keycode 35 = h H
keycode 36 = j J
keycode 37 = k K
keycode 38 = l L
keycode 39 = odiaeresis Odiaeresis
keycode 40 = adiaeresis Adiaeresis
keycode 41 = dead_circumflex degree
keycode 42 = Shift
keycode 43 = numbersign apostrophe
keycode 44 = y Y
keycode 45 = x X
keycode 46 = c C
keycode 47 = v V
keycode 48 = b B
keycode 49 = n N
keycode 50 = m M
keycode 51 = comma semicolon
keycode 52 = period colon
keycode 53 = minus underscore
keycode 54 = Shift
keycode 57 = space
EOF
gzip /tmp/de.kmap
mv /tmp/de.kmap.gz /usr/share/keymaps/i386/qwertz/de.kmap.gz 2>/dev/null || true
info "Fallback deutsche Keymap erstellt"
fi
fi
# Teste Keymap-Funktionalität
progress "Teste Keymap-Funktionalität..."
if command -v loadkeys &> /dev/null; then
if loadkeys de 2>/dev/null; then
info "✅ Deutsche Keymap erfolgreich geladen"
else
warning "⚠️ Deutsche Keymap konnte nicht geladen werden"
# Versuche alternative Keymaps
for alt_keymap in de-latin1 de_DE german; do
if loadkeys "$alt_keymap" 2>/dev/null; then
info "✅ Alternative Keymap '$alt_keymap' geladen"
break
fi
done
fi
fi
# Repariere localectl falls verfügbar
if command -v localectl &> /dev/null; then
progress "Repariere localectl-Konfiguration..."
# Erstelle systemd-localed Verzeichnis falls es fehlt
mkdir -p /etc/systemd/system/systemd-localed.service.d 2>/dev/null || true
# Versuche localectl zu reparieren
if ! localectl status &> /dev/null; then
warning "localectl nicht funktional - versuche Reparatur..."
# Starte systemd-localed Service
systemctl start systemd-localed 2>/dev/null || true
systemctl enable systemd-localed 2>/dev/null || true
# Warte kurz und versuche erneut
sleep 2
if localectl status &> /dev/null; then
info "✅ localectl repariert"
localectl set-keymap de 2>/dev/null || true
localectl set-x11-keymap de 2>/dev/null || true
else
warning "localectl bleibt nicht funktional - verwende alternative Methoden"
fi
else
info "✅ localectl funktional"
fi
fi
# Erstelle vconsole.conf für systemd-Systeme
progress "Konfiguriere vconsole.conf..."
cat > /etc/vconsole.conf << EOF
KEYMAP=de
FONT=eurlatgr
EOF
# Aktualisiere initramfs mit neuen Keymap-Einstellungen
if command -v update-initramfs &> /dev/null; then
progress "Aktualisiere initramfs..."
update-initramfs -u 2>/dev/null || warning "initramfs-Update fehlgeschlagen"
fi
log "✅ Keymap-Probleme behoben"
}
# ========================== HAUPTPROGRAMM ==========================
main() {
log "🚀 MYP Kiosk-Installation gestartet: $(date)"
check_root
detect_system
setup_system_basics
fix_keymap_issues
update_system
install_certificates
create_directory_structure
cleanup_system
install_packages
install_chromium
create_users
install_application
set_file_permissions
configure_kiosk
optimize_raspberry_pi
configure_dns_and_network
configure_autologin
configure_multiple_autostart
configure_autostart
configure_security
create_maintenance_tools
finalize_installation
show_installation_report
# Abschließende Frage
echo
read -p "🔄 System jetzt neustarten für Kiosk-Modus? (j/N): " reboot_choice
if [[ "$reboot_choice" =~ ^[jJ]$ ]]; then
log "🚀 Neustart für Kiosk-Modus..."
sleep 3
reboot
else
log "⚠️ Manueller Neustart erforderlich: sudo reboot"
fi
}
# ========================== PROGRAMMSTART ==========================
# Starte Installation
main "$@"
chmod +x /usr/local/bin/dns-health-check