Projektarbeit-MYP/backend/installer.sh
2025-05-31 22:40:29 +02:00

1195 lines
40 KiB
Bash

#!/bin/bash
# ===================================================================
# MYP Druckerverwaltung - VOLLSTÄNDIGER KIOSK-INSTALLER für Raspbian
# Entwickelt auf Windows, ausführbar auf Raspberry Pi / Debian
# OHNE virtualenv - verwendet System-Python mit --break-system-packages
# ECHTER KIOSK-MODUS: Entfernt Desktop, 3 Backend-Instanzen, Autologin
# ===================================================================
set -euo pipefail
# =========================== KONFIGURATION ===========================
APP_NAME="MYP Druckerverwaltung"
APP_DIR="/opt/myp"
SERVICE_NAME_KIOSK="myp-kiosk"
SERVICE_NAME_HTTPS="myp-https"
SERVICE_NAME_HTTP="myp-http"
KIOSK_USER="kiosk"
CURRENT_DIR="$(pwd)"
INSTALL_LOG="/var/log/myp-install.log"
# Farben für Ausgabe
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
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"
}
check_debian_system() {
if [ ! -f /etc/debian_version ]; then
error "Dieses Skript ist nur für Debian/Raspbian-Systeme geeignet!"
fi
log "✅ Debian/Raspbian-System erkannt"
}
# ========================== DESKTOP ENVIRONMENTS ENTFERNEN ==========================
remove_desktop_environments() {
log "=== ENTFERNE ALLE DESKTOP ENVIRONMENTS ==="
progress "Stoppe alle Desktop-Services..."
systemctl stop lightdm 2>/dev/null || true
systemctl stop gdm3 2>/dev/null || true
systemctl stop sddm 2>/dev/null || true
systemctl stop xdm 2>/dev/null || true
systemctl disable lightdm 2>/dev/null || true
systemctl disable gdm3 2>/dev/null || true
systemctl disable sddm 2>/dev/null || true
systemctl disable xdm 2>/dev/null || true
progress "Entferne Desktop-Pakete vollständig..."
# Raspberry Pi OS Desktop entfernen
apt-get remove --purge -y \
raspberrypi-ui-mods \
pi-package \
desktop-base \
lxde* \
xfce4* \
gnome* \
kde* \
mate* \
cinnamon* \
openbox \
pcmanfm \
file-manager* \
task-lxde-desktop \
task-xfce-desktop \
task-gnome-desktop \
task-kde-desktop \
2>/dev/null || true
# Display Manager entfernen
apt-get remove --purge -y \
lightdm* \
gdm3* \
sddm* \
xdm* \
nodm* \
2>/dev/null || true
# Unnötige Pakete entfernen
apt-get remove --purge -y \
libreoffice* \
thunderbird* \
firefox* \
vlc* \
gimp* \
scratch* \
minecraft-pi \
sonic-pi \
2>/dev/null || true
# Autoremove und Autoclean
apt-get autoremove --purge -y
apt-get autoclean
log "✅ Desktop Environments vollständig entfernt"
}
# ========================== KIOSK BENUTZER ERSTELLEN ==========================
create_kiosk_user() {
log "=== ERSTELLE KIOSK-BENUTZER ==="
# Kiosk-Benutzer erstellen falls nicht vorhanden
if ! id "$KIOSK_USER" &>/dev/null; then
progress "Erstelle Kiosk-Benutzer: $KIOSK_USER"
useradd -m -s /bin/bash "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen"
# Gruppen hinzufügen
usermod -aG audio,video,input,dialout,plugdev,users "$KIOSK_USER" 2>/dev/null || true
else
info "Kiosk-Benutzer $KIOSK_USER existiert bereits"
fi
# Passwort entfernen für automatischen Login
passwd -d "$KIOSK_USER" || warning "Konnte Passwort nicht entfernen"
log "✅ Kiosk-Benutzer erstellt: $KIOSK_USER"
}
# ========================== MINIMALE X11 INSTALLATION ==========================
install_minimal_x11() {
log "=== INSTALLIERE MINIMALE X11-UMGEBUNG ==="
progress "Installiere minimale X11-Pakete..."
apt-get install -y \
xserver-xorg-core \
xserver-xorg-input-all \
xserver-xorg-video-fbdev \
xserver-xorg-video-vesa \
xinit \
x11-xserver-utils \
xdotool \
unclutter \
openbox \
|| error "X11 Installation fehlgeschlagen"
# Chromium Browser mit Fallback-Mechanismus installieren
progress "Installiere Chromium Browser..."
if apt-get install -y chromium 2>/dev/null; then
log "✅ Chromium erfolgreich installiert"
elif apt-get install -y chromium-browser 2>/dev/null; then
log "✅ Chromium-Browser erfolgreich installiert"
elif apt-get install -y firefox-esr 2>/dev/null; then
warning "⚠️ Chromium nicht verfügbar - Firefox ESR als Fallback installiert"
# Firefox-Konfiguration für Kiosk-Modus anpassen
progress "Konfiguriere Firefox für Kiosk-Modus..."
FIREFOX_BROWSER="firefox-esr"
else
error "❌ Kein Browser verfügbar (chromium, chromium-browser, firefox-esr)"
fi
log "✅ Minimale X11-Umgebung installiert"
}
# ========================== MERCEDES ZERTIFIKATE ==========================
install_mercedes_certificates() {
log "=== INSTALLIERE MERCEDES SSL-ZERTIFIKATE ==="
progress "Aktualisiere CA-Zertifikate..."
# CA-Zertifikate Paket installieren/aktualisieren
apt-get install -y ca-certificates curl || error "CA-Zertifikate Installation fehlgeschlagen"
# Standard CA-Bundle aktualisieren
update-ca-certificates || warning "CA-Zertifikate Update teilweise fehlgeschlagen"
# Mercedes Corporate Zertifikate installieren (falls vorhanden)
if [ -d "$CURRENT_DIR/certs/mercedes" ] && [ "$(ls -A $CURRENT_DIR/certs/mercedes 2>/dev/null)" ]; then
progress "Installiere Mercedes Corporate Zertifikate..."
# Alle .crt und .pem Dateien kopieren
find "$CURRENT_DIR/certs/mercedes" -type f \( -name "*.crt" -o -name "*.pem" -o -name "*.cer" \) -exec cp {} /usr/local/share/ca-certificates/ \; 2>/dev/null || true
# Zertifikate aktualisieren
update-ca-certificates || warning "Mercedes Zertifikate Update fehlgeschlagen"
log "✅ Mercedes Zertifikate installiert"
else
info "Keine Mercedes Zertifikate gefunden - verwende Standard CA-Bundle"
fi
# Python SSL-Konfiguration optimieren
progress "Konfiguriere Python SSL-Einstellungen..."
# pip Konfiguration für SSL
mkdir -p /root/.pip
cat > /root/.pip/pip.conf << EOF
[global]
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
cert = /etc/ssl/certs/ca-certificates.crt
timeout = 60
retries = 3
[install]
trusted-host = pypi.org
pypi.python.org
files.pythonhosted.org
EOF
# Python HTTPS-Konfiguration
export SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt"
export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
export CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
# Pip auf neueste Version aktualisieren
progress "Aktualisiere pip auf neueste Version..."
python3 -m pip install --upgrade pip --break-system-packages --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org || warning "pip Update fehlgeschlagen"
# SSL-Test durchführen
progress "Teste SSL-Verbindung zu PyPI..."
if python3 -c "import ssl, urllib.request; urllib.request.urlopen('https://pypi.org')" 2>/dev/null; then
log "✅ SSL-Verbindung zu PyPI erfolgreich"
else
warning "⚠️ SSL-Verbindung zu PyPI problematisch - Installation wird dennoch versucht"
fi
log "✅ Mercedes SSL-Zertifikate und Python-Konfiguration abgeschlossen"
}
# ========================== ABHÄNGIGKEITEN INSTALLIEREN ==========================
install_system_dependencies() {
log "=== INSTALLIERE SYSTEM-ABHÄNGIGKEITEN ==="
progress "Aktualisiere Paketlisten..."
apt-get update -y || error "APT Update fehlgeschlagen"
progress "Installiere Python 3 und grundlegende Pakete..."
apt-get install -y \
python3 \
python3-pip \
python3-dev \
python3-setuptools \
build-essential \
libssl-dev \
libffi-dev \
git \
curl \
wget \
nano \
htop \
rsync \
unzip \
sudo \
systemd \
ca-certificates \
gnupg \
lsb-release \
sqlite3 \
|| error "System-Pakete Installation fehlgeschlagen"
# ========================== NODE.JS UND NPM INSTALLATION ==========================
progress "Installiere Node.js und npm..."
# NodeSource Repository für neueste LTS Version hinzufügen
progress "Füge NodeSource Repository hinzu..."
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - || {
warning "NodeSource Repository konnte nicht hinzugefügt werden - verwende Debian-Pakete"
apt-get install -y nodejs npm || error "Node.js Installation aus Debian-Repository fehlgeschlagen"
}
# Node.js aus NodeSource Repository installieren (falls Repository erfolgreich hinzugefügt)
if [ -f /etc/apt/sources.list.d/nodesource.list ]; then
progress "Installiere Node.js LTS aus NodeSource Repository..."
apt-get update -y
apt-get install -y nodejs || error "Node.js Installation aus NodeSource fehlgeschlagen"
fi
# Überprüfe Node.js und npm Installation
if command -v node >/dev/null 2>&1; then
NODE_VERSION=$(node --version)
log "✅ Node.js erfolgreich installiert: $NODE_VERSION"
else
error "❌ Node.js Installation fehlgeschlagen"
fi
if command -v npm >/dev/null 2>&1; then
NPM_VERSION=$(npm --version)
log "✅ npm erfolgreich installiert: $NPM_VERSION"
# npm auf neueste Version aktualisieren
progress "Aktualisiere npm auf neueste Version..."
npm install -g npm@latest || warning "npm Update fehlgeschlagen"
NPM_VERSION_NEW=$(npm --version)
log "✅ npm aktualisiert: $NPM_VERSION_NEW"
else
error "❌ npm Installation fehlgeschlagen"
fi
# npm-Konfiguration für bessere Performance und Sicherheit
progress "Konfiguriere npm-Einstellungen..."
npm config set fund false
npm config set audit-level moderate
npm config set package-lock true
npm config set save-exact true
# WICHTIG: Mercedes Zertifikate vor Python-Paketen installieren
install_mercedes_certificates
progress "Installiere Python-Abhängigkeiten mit Mercedes SSL-Konfiguration..."
# SSL-freundliche pip-Installation mit Fallback-Optionen
PIP_OPTS="--break-system-packages --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --timeout 60 --retries 3"
# Core Flask Framework
pip3 install $PIP_OPTS Flask==3.1.1 || pip3 install $PIP_OPTS Flask || error "Flask Installation fehlgeschlagen"
pip3 install $PIP_OPTS Flask-Login==0.6.3 || pip3 install $PIP_OPTS Flask-Login || error "Flask-Login Installation fehlgeschlagen"
pip3 install $PIP_OPTS Flask-WTF==1.2.1 || pip3 install $PIP_OPTS Flask-WTF || error "Flask-WTF Installation fehlgeschlagen"
# Datenbank
pip3 install $PIP_OPTS SQLAlchemy==2.0.36 || pip3 install $PIP_OPTS SQLAlchemy || error "SQLAlchemy Installation fehlgeschlagen"
# Sicherheit
pip3 install $PIP_OPTS bcrypt==4.2.1 || pip3 install $PIP_OPTS bcrypt || error "bcrypt Installation fehlgeschlagen"
pip3 install $PIP_OPTS cryptography==44.0.0 || pip3 install $PIP_OPTS cryptography || error "cryptography Installation fehlgeschlagen"
pip3 install $PIP_OPTS Werkzeug==3.1.3 || pip3 install $PIP_OPTS Werkzeug || error "Werkzeug Installation fehlgeschlagen"
# Smart Plug Steuerung
pip3 install $PIP_OPTS PyP100 || warning "PyP100 Installation fehlgeschlagen (optional)"
# HTTP Requests
pip3 install $PIP_OPTS requests==2.32.3 || pip3 install $PIP_OPTS requests || error "requests Installation fehlgeschlagen"
# System Monitoring
pip3 install $PIP_OPTS psutil==6.1.1 || pip3 install $PIP_OPTS psutil || error "psutil Installation fehlgeschlagen"
# Redis (optional)
pip3 install $PIP_OPTS redis==5.2.1 || warning "redis Installation fehlgeschlagen (optional)"
# Weitere Core-Abhängigkeiten
pip3 install $PIP_OPTS MarkupSafe==3.0.2 || pip3 install $PIP_OPTS MarkupSafe || error "MarkupSafe Installation fehlgeschlagen"
# Produktions-Server
pip3 install $PIP_OPTS gunicorn==23.0.0 || pip3 install $PIP_OPTS gunicorn || error "gunicorn Installation fehlgeschlagen"
# ========================== NPM-ABHÄNGIGKEITEN INSTALLIEREN ==========================
progress "Prüfe auf package.json für npm-Abhängigkeiten..."
if [ -f "$CURRENT_DIR/package.json" ]; then
progress "package.json gefunden - installiere npm-Abhängigkeiten..."
cd "$CURRENT_DIR"
# npm install OHNE --production um auch devDependencies (TailwindCSS) zu installieren
progress "Installiere alle npm-Abhängigkeiten (inklusive devDependencies für TailwindCSS)..."
npm install --no-optional --no-audit --no-fund || {
warning "npm install fehlgeschlagen - versuche mit --legacy-peer-deps"
npm install --no-optional --no-audit --no-fund --legacy-peer-deps || error "npm install komplett fehlgeschlagen"
}
log "✅ npm-Abhängigkeiten erfolgreich installiert:"
log " 📦 Dependencies: FontAwesome, FullCalendar, Chart.js, Vite"
log " 🛠️ DevDependencies: TailwindCSS, PostCSS, Autoprefixer"
# Überprüfe TailwindCSS Installation speziell
if npx tailwindcss --help >/dev/null 2>&1; then
log "✅ TailwindCSS erfolgreich installiert und verfügbar"
else
error "❌ TailwindCSS nicht verfügbar - Build wird fehlschlagen"
fi
# Überprüfe auf Build-Scripts und führe sie aus
if npm run | grep -q "build:css"; then
progress "CSS-Build-Script gefunden - führe npm run build:css aus..."
npm run build:css || error "npm run build:css fehlgeschlagen - TailwindCSS Build nicht möglich"
log "✅ TailwindCSS Build abgeschlossen - CSS-Dateien generiert"
fi
if npm run | grep -q "build" && ! npm run | grep -q "build:css"; then
progress "Haupt-Build-Script gefunden - führe npm run build aus..."
npm run build || warning "npm run build fehlgeschlagen"
log "✅ Frontend-Build abgeschlossen"
fi
# Überprüfe generierte CSS-Dateien
if [ -f "$CURRENT_DIR/static/css/tailwind.min.css" ]; then
TAILWIND_SIZE=$(du -h "$CURRENT_DIR/static/css/tailwind.min.css" | cut -f1)
log "✅ TailwindCSS erfolgreich kompiliert: tailwind.min.css ($TAILWIND_SIZE)"
else
warning "⚠️ tailwind.min.css nicht gefunden - CSS-Build möglicherweise fehlgeschlagen"
fi
else
info "Keine package.json gefunden - überspringe npm-Abhängigkeiten"
fi
log "✅ Alle Abhängigkeiten (Python + Node.js + npm) erfolgreich installiert"
}
# ========================== 3 BACKEND SERVICES ERSTELLEN ==========================
create_backend_services() {
log "=== ERSTELLE 3 BACKEND-SERVICES ==="
# Python-Startskripte für die verschiedenen Ports erstellen
progress "Erstelle Python-Startskripte..."
# HTTPS-Startskript (Port 443)
cat > "$APP_DIR/start_https.py" << 'EOF'
#!/usr/bin/env python3
import sys
import os
# Füge App-Verzeichnis zum Python-Pfad hinzu
sys.path.insert(0, '/opt/myp')
# Setze Umgebungsvariablen
os.environ['FLASK_PORT'] = '443'
os.environ['FLASK_HOST'] = '0.0.0.0'
os.environ['FLASK_ENV'] = 'production'
try:
from app import app, get_ssl_context
ssl_context = get_ssl_context()
if ssl_context:
print("Starte HTTPS-Server auf Port 443...")
app.run(host='0.0.0.0', port=443, debug=False, ssl_context=ssl_context, threaded=True)
else:
print('SSL-Kontext nicht verfügbar')
sys.exit(1)
except Exception as e:
print(f"Fehler beim Starten des HTTPS-Servers: {e}")
sys.exit(1)
EOF
# HTTP-Startskript (Port 80)
cat > "$APP_DIR/start_http.py" << 'EOF'
#!/usr/bin/env python3
import sys
import os
# Füge App-Verzeichnis zum Python-Pfad hinzu
sys.path.insert(0, '/opt/myp')
# Setze Umgebungsvariablen
os.environ['FLASK_PORT'] = '80'
os.environ['FLASK_HOST'] = '0.0.0.0'
os.environ['FLASK_ENV'] = 'production'
try:
from app import app
print("Starte HTTP-Server auf Port 80...")
app.run(host='0.0.0.0', port=80, debug=False, threaded=True)
except Exception as e:
print(f"Fehler beim Starten des HTTP-Servers: {e}")
sys.exit(1)
EOF
# Skripte ausführbar machen
chmod +x "$APP_DIR/start_https.py"
chmod +x "$APP_DIR/start_http.py"
# Service 1: Kiosk-Backend (Port 5000)
progress "Erstelle myp-kiosk.service (Port 5000)..."
cat > "/etc/systemd/system/${SERVICE_NAME_KIOSK}.service" << EOF
[Unit]
Description=MYP Kiosk Backend (Port 5000)
After=network.target network-online.target
Wants=network-online.target
Requires=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=$APP_DIR
ExecStart=/usr/bin/python3 $APP_DIR/app.py --debug
Restart=always
RestartSec=5
StartLimitBurst=5
StartLimitInterval=60
# Umgebungsvariablen
Environment=PYTHONUNBUFFERED=1
Environment=FLASK_ENV=production
Environment=FLASK_HOST=0.0.0.0
Environment=FLASK_PORT=5000
Environment=PYTHONPATH=$APP_DIR
Environment=LC_ALL=C.UTF-8
Environment=LANG=C.UTF-8
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myp-kiosk
# Security-Einstellungen
NoNewPrivileges=true
PrivateTmp=false
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
# Service 2: HTTPS-Backend (Port 443)
progress "Erstelle myp-https.service (Port 443)..."
cat > "/etc/systemd/system/${SERVICE_NAME_HTTPS}.service" << EOF
[Unit]
Description=MYP HTTPS Backend (Port 443)
After=network.target network-online.target
Wants=network-online.target
Requires=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=$APP_DIR
ExecStart=/usr/bin/python3 $APP_DIR/start_https.py
Restart=always
RestartSec=5
StartLimitBurst=5
StartLimitInterval=60
# Umgebungsvariablen
Environment=PYTHONUNBUFFERED=1
Environment=FLASK_ENV=production
Environment=FLASK_HOST=0.0.0.0
Environment=FLASK_PORT=443
Environment=PYTHONPATH=$APP_DIR
Environment=LC_ALL=C.UTF-8
Environment=LANG=C.UTF-8
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myp-https
# Security-Einstellungen
NoNewPrivileges=true
PrivateTmp=false
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
# Service 3: HTTP-Backend (Port 80)
progress "Erstelle myp-http.service (Port 80)..."
cat > "/etc/systemd/system/${SERVICE_NAME_HTTP}.service" << EOF
[Unit]
Description=MYP HTTP Backend (Port 80)
After=network.target network-online.target
Wants=network-online.target
Requires=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=$APP_DIR
ExecStart=/usr/bin/python3 $APP_DIR/start_http.py
Restart=always
RestartSec=5
StartLimitBurst=5
StartLimitInterval=60
# Umgebungsvariablen
Environment=PYTHONUNBUFFERED=1
Environment=FLASK_ENV=production
Environment=FLASK_HOST=0.0.0.0
Environment=FLASK_PORT=80
Environment=PYTHONPATH=$APP_DIR
Environment=LC_ALL=C.UTF-8
Environment=LANG=C.UTF-8
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myp-http
# Security-Einstellungen
NoNewPrivileges=true
PrivateTmp=false
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
log "✅ 3 Backend-Services mit separaten Python-Skripten erstellt"
}
# ========================== AUTOLOGIN KONFIGURIEREN ==========================
configure_autologin() {
log "=== KONFIGURIERE AUTOLOGIN ==="
progress "Erstelle Autologin-Service..."
# Getty-Service für automatischen Login überschreiben
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 linux
EOF
# Systemd Target auf Multi-User setzen (ohne grafisches Login)
systemctl set-default multi-user.target
log "✅ Autologin konfiguriert für Benutzer: $KIOSK_USER"
}
# ========================== KIOSK BROWSER KONFIGURATION ==========================
configure_kiosk_browser() {
log "=== KONFIGURIERE KIOSK-BROWSER ==="
KIOSK_HOME="/home/$KIOSK_USER"
# Openbox-Konfiguration für randlosen Vollbildmodus
progress "Konfiguriere Openbox für randlosen Vollbildmodus..."
mkdir -p "$KIOSK_HOME/.config/openbox"
cat > "$KIOSK_HOME/.config/openbox/rc.xml" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<openbox_config xmlns="http://openbox.org/3.4/rc" xmlns:xi="http://www.w3.org/2001/XInclude">
<resistance>
<strength>10</strength>
<screen_edge_strength>20</screen_edge_strength>
</resistance>
<focus>
<focusNew>yes</focusNew>
<followMouse>no</followMouse>
</focus>
<placement>
<policy>Smart</policy>
<center>yes</center>
</placement>
<theme>
<name>Clearlooks</name>
<titleLayout>NLIMC</titleLayout>
<keepBorder>no</keepBorder>
<animateIconify>yes</animateIconify>
</theme>
<desktops>
<number>1</number>
<firstdesk>1</firstdesk>
<names>
<name>Desktop 1</name>
</names>
<popupTime>875</popupTime>
</desktops>
<resize>
<drawContents>yes</drawContents>
<popupShow>Nonpixel</popupShow>
<popupPosition>Center</popupPosition>
</resize>
<margins>
<top>0</top>
<bottom>0</bottom>
<left>0</left>
<right>0</right>
</margins>
<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>
<!-- Deaktiviere alle Tastenkombinationen für Kiosk-Sicherheit -->
</keyboard>
<mouse>
<dragThreshold>8</dragThreshold>
<doubleClickTime>200</doubleClickTime>
<screenEdgeWarpTime>400</screenEdgeWarpTime>
</mouse>
<applications>
<!-- Chromium/Browser Konfiguration -->
<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>
<layer>above</layer>
</application>
<application name="firefox*">
<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>
<layer>above</layer>
</application>
</applications>
</openbox_config>
EOF
# .bashrc für automatischen X-Start erweitern
progress "Konfiguriere automatischen X-Start..."
cat >> "$KIOSK_HOME/.bashrc" << 'EOF'
# Automatischer X-Start für Kiosk-Modus
if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then
exec startx
fi
EOF
# .xinitrc für Kiosk-Session erstellen
progress "Erstelle optimierte Kiosk X-Session..."
cat > "$KIOSK_HOME/.xinitrc" << 'EOF'
#!/bin/bash
# Bildschirmauflösung automatisch erkennen
RESOLUTION=$(xrandr | grep '*' | head -1 | awk '{print $1}')
if [ -z "$RESOLUTION" ]; then
RESOLUTION="1920x1080" # Fallback-Auflösung
fi
WIDTH=$(echo $RESOLUTION | cut -d'x' -f1)
HEIGHT=$(echo $RESOLUTION | cut -d'x' -f2)
echo "Erkannte Bildschirmauflösung: ${WIDTH}x${HEIGHT}"
# Bildschirmschoner und Energieverwaltung komplett deaktivieren
xset s off
xset s noblank
xset s noexpose
xset -dpms
xset s 0 0
# Mauszeiger verstecken (aggressiver)
unclutter -idle 0.1 -root -noevents &
# Openbox im Hintergrund starten
openbox &
# Warte auf Backend-Services
echo "Warte auf MYP Backend-Services..."
WAIT_COUNT=0
while ! curl -s http://localhost:5000 > /dev/null; do
echo "Warte auf Backend (Port 5000)... ($WAIT_COUNT/60)"
sleep 2
WAIT_COUNT=$((WAIT_COUNT + 1))
if [ $WAIT_COUNT -gt 60 ]; then
echo "FEHLER: Backend nach 120s nicht erreichbar!"
break
fi
done
echo "Backend erreichbar - starte Kiosk-Browser..."
# Browser-Erkennung und -Start mit optimierten Vollbild-Flags
if command -v chromium >/dev/null 2>&1; then
echo "Starte Chromium Browser mit Auflösung ${WIDTH}x${HEIGHT}..."
exec chromium \
--kiosk \
--no-sandbox \
--disable-infobars \
--disable-session-crashed-bubble \
--disable-restore-session-state \
--disable-web-security \
--disable-features=TranslateUI \
--disable-extensions \
--disable-plugins \
--disable-popup-blocking \
--disable-prompt-on-repost \
--disable-sync \
--disable-translate \
--noerrdialogs \
--no-first-run \
--no-default-browser-check \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--start-maximized \
--window-size=${WIDTH},${HEIGHT} \
--window-position=0,0 \
--user-data-dir=/home/kiosk/.chromium-kiosk \
--disable-background-mode \
--force-device-scale-factor=1.0 \
--disable-pinch \
--overscroll-history-navigation=0 \
--disable-dev-shm-usage \
--memory-pressure-off \
--max_old_space_size=512 \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--disable-features=VizDisplayCompositor \
--enable-features=OverlayScrollbar \
--hide-scrollbars \
http://localhost:5000
elif command -v chromium-browser >/dev/null 2>&1; then
echo "Starte Chromium-Browser mit Auflösung ${WIDTH}x${HEIGHT}..."
exec chromium-browser \
--kiosk \
--no-sandbox \
--disable-infobars \
--disable-session-crashed-bubble \
--disable-restore-session-state \
--disable-web-security \
--disable-features=TranslateUI \
--disable-extensions \
--disable-plugins \
--disable-popup-blocking \
--disable-prompt-on-repost \
--disable-sync \
--disable-translate \
--noerrdialogs \
--no-first-run \
--no-default-browser-check \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--start-maximized \
--window-size=${WIDTH},${HEIGHT} \
--window-position=0,0 \
--user-data-dir=/home/kiosk/.chromium-kiosk \
--disable-background-mode \
--force-device-scale-factor=1.0 \
--disable-pinch \
--overscroll-history-navigation=0 \
--disable-dev-shm-usage \
--memory-pressure-off \
--max_old_space_size=512 \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--disable-features=VizDisplayCompositor \
--enable-features=OverlayScrollbar \
--hide-scrollbars \
http://localhost:5000
elif command -v firefox-esr >/dev/null 2>&1; then
echo "Starte Firefox ESR mit Auflösung ${WIDTH}x${HEIGHT}..."
# Firefox-Profil für Kiosk erstellen
mkdir -p /home/kiosk/.mozilla/firefox/kiosk.default
cat > /home/kiosk/.mozilla/firefox/kiosk.default/user.js << FIREFOXEOF
user_pref("browser.shell.checkDefaultBrowser", false);
user_pref("browser.startup.homepage", "http://localhost:5000");
user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
user_pref("browser.tabs.warnOnClose", false);
user_pref("browser.sessionstore.resume_from_crash", false);
user_pref("security.tls.insecure_fallback_hosts", "localhost");
user_pref("browser.cache.disk.enable", false);
user_pref("browser.cache.memory.enable", true);
user_pref("browser.cache.offline.enable", false);
user_pref("network.http.use-cache", false);
user_pref("browser.fullscreen.autohide", true);
user_pref("dom.disable_open_during_load", false);
user_pref("privacy.popups.disable_from_plugins", 0);
user_pref("dom.popup_maximum", 0);
FIREFOXEOF
# Firefox CSS für randlosen Vollbildmodus
mkdir -p /home/kiosk/.mozilla/firefox/kiosk.default/chrome
cat > /home/kiosk/.mozilla/firefox/kiosk.default/chrome/userChrome.css << FIREFOXCSS
/* Firefox Kiosk Mode - Hide all UI elements */
#navigator-toolbox { display: none !important; }
#sidebar-box { display: none !important; }
#urlbar-container { display: none !important; }
#TabsToolbar { display: none !important; }
#nav-bar { display: none !important; }
#PersonalToolbar { display: none !important; }
.toolbar-items { display: none !important; }
#main-window[sizemode="fullscreen"] .tabbrowser-tab {
visibility: collapse !important;
}
FIREFOXCSS
exec firefox-esr \
--kiosk \
--width=${WIDTH} \
--height=${HEIGHT} \
--profile /home/kiosk/.mozilla/firefox/kiosk.default \
http://localhost:5000
else
echo "FEHLER: Kein Browser verfügbar!"
exit 1
fi
EOF
# Berechtigungen setzen
chmod +x "$KIOSK_HOME/.xinitrc"
chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME"
log "✅ Kiosk-Browser mit optimiertem Vollbildmodus konfiguriert"
}
# ========================== PRODUKTIONS-KIOSK SETUP ==========================
setup_production_kiosk() {
log "=== RICHTE PRODUKTIONS-KIOSK-MODUS EIN ==="
# 1. System-Abhängigkeiten installieren
install_system_dependencies
# 2. Desktop-Environments entfernen
remove_desktop_environments
# 3. Minimale X11-Umgebung installieren
install_minimal_x11
# 4. Kiosk-Benutzer erstellen
create_kiosk_user
# 5. Anwendung kopieren
progress "Erstelle Zielverzeichnis /opt/myp..."
mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen"
progress "Kopiere Projektdateien selektiv nach $APP_DIR..."
# Liste der zu kopierenden Dateien/Ordner (ohne unnötige Inhalte)
declare -a COPY_ITEMS=(
"app.py"
"models.py"
"requirements.txt"
"blueprints/"
"config/"
"database/"
"docs/"
"static/"
"templates/"
"uploads/"
"utils/"
"logs/"
"certs/"
)
# Sichere selektive Kopie
for item in "${COPY_ITEMS[@]}"; do
if [ -e "$CURRENT_DIR/$item" ]; then
progress "Kopiere: $item"
cp -r "$CURRENT_DIR/$item" "$APP_DIR/" || warning "Fehler beim Kopieren von $item"
else
info "Überspringe nicht vorhandenes Element: $item"
fi
done
# Spezielle Dateien einzeln kopieren (falls vorhanden)
for file in "package.json" "package-lock.json" "tailwind.config.js" "postcss.config.js"; do
if [ -f "$CURRENT_DIR/$file" ]; then
cp "$CURRENT_DIR/$file" "$APP_DIR/" || warning "Fehler beim Kopieren von $file"
fi
done
# Stelle sicher, dass app.py ausführbar ist
chmod +x "$APP_DIR/app.py" || error "Konnte app.py nicht ausführbar machen"
# Erstelle notwendige Verzeichnisse falls sie nicht existieren
mkdir -p "$APP_DIR/database/backups"
mkdir -p "$APP_DIR/logs/app"
mkdir -p "$APP_DIR/logs/auth"
mkdir -p "$APP_DIR/logs/errors"
mkdir -p "$APP_DIR/uploads/temp"
# Berechtigungen setzen
chown -R root:root "$APP_DIR"
chmod -R 755 "$APP_DIR"
chmod 750 "$APP_DIR/database"
chmod 750 "$APP_DIR/logs"
chmod 755 "$APP_DIR/uploads"
# 6. Backend-Services erstellen
create_backend_services
# 7. Autologin konfigurieren
configure_autologin
# 8. Kiosk-Browser konfigurieren
configure_kiosk_browser
# 9. Services aktivieren und starten
progress "Lade Systemd-Konfiguration neu..."
systemctl daemon-reload || error "Systemd Reload fehlgeschlagen"
progress "Aktiviere alle Backend-Services..."
systemctl enable "$SERVICE_NAME_KIOSK.service" || error "Kiosk-Service Enable fehlgeschlagen"
systemctl enable "$SERVICE_NAME_HTTPS.service" || error "HTTPS-Service Enable fehlgeschlagen"
systemctl enable "$SERVICE_NAME_HTTP.service" || error "HTTP-Service Enable fehlgeschlagen"
progress "Starte alle Backend-Services..."
systemctl start "$SERVICE_NAME_KIOSK.service" || error "Kiosk-Service Start fehlgeschlagen"
systemctl start "$SERVICE_NAME_HTTPS.service" || warning "HTTPS-Service Start fehlgeschlagen (SSL möglicherweise nicht konfiguriert)"
systemctl start "$SERVICE_NAME_HTTP.service" || error "HTTP-Service Start fehlgeschlagen"
# Service-Status prüfen
sleep 5
info "=== SERVICE-STATUS ==="
for service in "$SERVICE_NAME_KIOSK" "$SERVICE_NAME_HTTPS" "$SERVICE_NAME_HTTP"; do
if systemctl is-active --quiet "$service.service"; then
log "$service Service läuft erfolgreich"
else
warning "⚠️ $service Service läuft nicht - prüfen Sie die Logs: journalctl -u $service -f"
fi
done
# Backend-Tests
progress "Teste Backend-Erreichbarkeit..."
sleep 3
if curl -s http://localhost:5000 > /dev/null 2>&1; then
log "✅ Port 5000 (Kiosk) erreichbar"
else
warning "⚠️ Port 5000 (Kiosk) nicht erreichbar"
fi
if curl -s http://localhost:80 > /dev/null 2>&1; then
log "✅ Port 80 (HTTP) erreichbar"
else
warning "⚠️ Port 80 (HTTP) nicht erreichbar"
fi
if curl -k -s https://localhost:443 > /dev/null 2>&1; then
log "✅ Port 443 (HTTPS) erreichbar"
else
warning "⚠️ Port 443 (HTTPS) nicht erreichbar (SSL möglicherweise nicht konfiguriert)"
fi
log "✅ PRODUKTIONS-KIOSK-MODUS ERFOLGREICH EINGERICHTET"
log ""
log "🚀 WICHTIG: NEUSTART ERFORDERLICH!"
log " sudo reboot"
log ""
log "📊 NACH DEM NEUSTART:"
log " • Automatischer Login als Benutzer: $KIOSK_USER"
log " • Automatischer X-Start und Chromium-Kiosk"
log " • Backend läuft auf 3 Ports:"
log " - http://localhost:5000 (Kiosk-Anzeige)"
log " - http://localhost:80 (HTTP-API)"
log " - https://localhost:443 (HTTPS-API)"
log ""
log "🔧 SERVICE-BEFEHLE:"
log " • Status: sudo systemctl status myp-{kiosk,https,http}"
log " • Logs: sudo journalctl -u myp-kiosk -f"
log " • Restart: sudo systemctl restart myp-{kiosk,https,http}"
log ""
warning "🔄 FÜHRE JETZT 'sudo reboot' AUS, UM DEN KIOSK-MODUS ZU AKTIVIEREN!"
}
# ========================== HAUPTMENÜ ==========================
show_menu() {
clear
echo -e "${BLUE}=================================================================${NC}"
echo -e "${GREEN} $APP_NAME - VOLLSTÄNDIGER KIOSK-INSTALLER${NC}"
echo -e "${BLUE}=================================================================${NC}"
echo ""
echo -e "${YELLOW}Aktuelles Verzeichnis:${NC} $CURRENT_DIR"
echo -e "${YELLOW}Systemzeit:${NC} $(date)"
echo -e "${YELLOW}Zielverzeichnis:${NC} $APP_DIR"
echo -e "${YELLOW}Kiosk-Benutzer:${NC} $KIOSK_USER"
echo ""
echo -e "${PURPLE}Wählen Sie eine Option:${NC}"
echo ""
echo -e "${GREEN}1)${NC} System vorbereiten (Abhängigkeiten installieren)"
echo -e " → Installiert Python 3, pip und alle benötigten Pakete"
echo -e " → Verwendet: pip install --break-system-packages"
echo -e " → Mercedes SSL-Zertifikate werden konfiguriert"
echo ""
echo -e "${GREEN}2)${NC} VOLLSTÄNDIGER KIOSK-MODUS installieren"
echo -e "${RED}ENTFERNT ALLE DESKTOP-ENVIRONMENTS!${NC}"
echo -e " → Installiert minimale X11-Umgebung"
echo -e " → Erstellt 3 Backend-Services (Port 5000, 80, 443)"
echo -e " → Konfiguriert Autologin und Kiosk-Browser"
echo -e "${YELLOW}NEUSTART ERFORDERLICH!${NC}"
echo ""
echo -e "${RED}0)${NC} Beenden"
echo ""
echo -e "${RED}⚠️ WARNUNG: Option 2 macht Raspberry Pi zu reinem Kiosk-System!${NC}"
echo -e "${BLUE}=================================================================${NC}"
echo -n "Ihre Wahl [0-2]: "
}
# ========================== MAIN LOGIC ==========================
main() {
# System-Checks
check_root
check_debian_system
# Erstelle Log-Datei
mkdir -p "$(dirname "$INSTALL_LOG")"
touch "$INSTALL_LOG"
log "=== MYP VOLLSTÄNDIGER KIOSK-INSTALLER GESTARTET ==="
log "Arbeitsverzeichnis: $CURRENT_DIR"
log "Zielverzeichnis: $APP_DIR"
log "Kiosk-Services: $SERVICE_NAME_KIOSK, $SERVICE_NAME_HTTPS, $SERVICE_NAME_HTTP"
log "Kiosk-Benutzer: $KIOSK_USER"
log "System: $(uname -a)"
log "Debian-Version: $(cat /etc/debian_version 2>/dev/null || echo 'Unbekannt')"
while true; do
show_menu
read -r choice
case $choice in
1)
clear
log "=== OPTION 1: SYSTEM VORBEREITEN ==="
install_system_dependencies
echo ""
echo -e "${GREEN}✅ System-Vorbereitung abgeschlossen!${NC}"
echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}"
read -r
;;
2)
clear
echo -e "${RED}⚠️ WARNUNG: Sie sind dabei, alle Desktop-Environments zu entfernen!${NC}"
echo -e "${YELLOW}Der Raspberry Pi wird zu einem reinen Kiosk-System umgebaut.${NC}"
echo -e "${BLUE}Nach der Installation startet automatisch der Kiosk-Browser.${NC}"
echo ""
echo -n "Sind Sie sicher? [ja/NEIN]: "
read -r confirm
if [ "$confirm" = "ja" ] || [ "$confirm" = "JA" ]; then
clear
log "=== OPTION 2: VOLLSTÄNDIGER KIOSK-MODUS ==="
setup_production_kiosk
echo ""
echo -e "${GREEN}✅ KIOSK-MODUS ERFOLGREICH EINGERICHTET!${NC}"
echo -e "${RED}🔄 NEUSTART JETZT ERFORDERLICH: sudo reboot${NC}"
echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}"
read -r
else
echo -e "${BLUE}Installation abgebrochen.${NC}"
sleep 2
fi
;;
0)
log "=== INSTALLER BEENDET ==="
echo -e "${GREEN}Auf Wiedersehen!${NC}"
echo -e "${BLUE}Log-Datei: $INSTALL_LOG${NC}"
exit 0
;;
*)
echo -e "${RED}Ungültige Eingabe. Bitte wählen Sie 0-2.${NC}"
sleep 2
;;
esac
done
}
# Script starten
main "$@"