#!/bin/bash # ============================================================================ # TESM-Lizenzserver — Installer/Updater # Richtet System-Pakete und die Flask-App (systemd + nginx) unter # /srv/tesm-license ein. Ursprünglich als Teil des TESM-Hauptrepos gebaut # (Fork von dessen install.sh) und später in dieses eigenständige Repo # ausgelagert -- Backup + Health-Check + automatischer Rückroll bei einem # fehlgeschlagenen Update funktionieren identisch zu TESMs eigenem # Installer, hier nur die Kurzfassung je Schritt. # # Auszuführen als root, nachdem dieses Repo/Release-Paket z.B. nach # /root/tesm-license entpackt wurde: # sudo ./install.sh # ============================================================================ set -e REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' print_status() { echo -e "${GREEN}✔${NC} ${1} completed."; } step() { echo -e "${RED}→${NC} ${1}..." | tee -a /var/log/tesm-license-install.log; } install_if_changed() { local src="$1" dst="$2" mode="${3:-644}" if [ -f "$dst" ] && cmp -s "$src" "$dst"; then return 1 fi sudo install -m "$mode" "$src" "$dst" return 0 } clear 2>/dev/null || true # ---- Bestehende Installation erkennen ---- EXISTING_INSTALL=0 [ -f /srv/tesm-license/sqlite.db ] && EXISTING_INSTALL=1 NEEDS_MIGRATION_GUARD=0 BACKUP_DIR="" if [ "$EXISTING_INSTALL" -eq 1 ]; then OLD_SCHEMA_VERSION="" [ -f /srv/tesm-license/SCHEMA_VERSION ] && OLD_SCHEMA_VERSION="$(tr -d '[:space:]' < /srv/tesm-license/SCHEMA_VERSION)" NEW_SCHEMA_VERSION="" [ -f "$REPO_DIR/srv/tesm-license/SCHEMA_VERSION" ] && NEW_SCHEMA_VERSION="$(tr -d '[:space:]' < "$REPO_DIR/srv/tesm-license/SCHEMA_VERSION")" step "Stopping tesm-license.service for update" systemctl stop tesm-license.service 2>/dev/null || true print_status "Service stopped" if [ -n "$OLD_SCHEMA_VERSION" ] && [ -n "$NEW_SCHEMA_VERSION" ] && [ "$OLD_SCHEMA_VERSION" == "$NEW_SCHEMA_VERSION" ]; then echo -e "${GREEN}Bestehende Installation erkannt, Datenbank-Schema unverändert (Version ${OLD_SCHEMA_VERSION}):${NC} In-Place-Update." else echo -e "${YELLOW}Bestehende Installation erkannt, Schema-Version geändert oder unbekannt:${NC} Update mit automatischer Migration." fi NEEDS_MIGRATION_GUARD=1 BACKUP_DIR="/srv/tesm-license-backup-pre-update-$(date +%Y%m%d-%H%M%S)" step "Backing up current installation to $BACKUP_DIR before update" cp -a /srv/tesm-license "$BACKUP_DIR" print_status "Backup created" fi # ---- Pakete ---- step "Installing system packages" sudo apt-get update >>/var/log/tesm-license-install.log 2>&1 && print_status "apt update" sudo apt-get install -y python3 python3-venv python3-pip nginx sqlite3 rsync logrotate certbot >>/var/log/tesm-license-install.log 2>&1 && print_status "Packages installed" # ---- Log-Verzeichnis ---- sudo mkdir -p /var/log/tesm-license sudo chmod 755 /var/log/tesm-license # ---- App-Verzeichnis ---- step "Deploying application to /srv/tesm-license" sudo mkdir -p /srv/tesm-license sudo rsync -a --delete --exclude 'venv' --exclude 'sqlite.db' --exclude 'fernet.key' --exclude 'secret.key' \ --exclude 'license.json' --exclude 'master_signing_key.json' \ "$REPO_DIR/srv/tesm-license/" /srv/tesm-license/ >>/var/log/tesm-license-install.log 2>&1 print_status "Application files copied" # ---- Python venv ---- step "Setting up Python virtual environment" cd /srv/tesm-license sudo python3 -m venv venv sudo ./venv/bin/python3 -m pip install --upgrade pip >>/var/log/tesm-license-install.log 2>&1 sudo ./venv/bin/python3 -m pip install -r requirements.txt >>/var/log/tesm-license-install.log 2>&1 print_status "Virtual environment ready" # ---- Datenbank ---- if [ ! -f /srv/tesm-license/sqlite.db ]; then step "Initializing database" sudo ./venv/bin/python3 create_db.py >>/var/log/tesm-license-install.log 2>&1 print_status "Database initialized" echo -e "${RED}→${NC} Kein Admin-Benutzer vorhanden. Bitte danach ausführen:" echo " sudo /srv/tesm-license/venv/bin/python3 /srv/tesm-license/create_admin.py" echo -e "${RED}→${NC} Und die eigene Bootstrap-Lizenz erzeugen:" echo " sudo /srv/tesm-license/venv/bin/python3 /srv/tesm-license/create_master_license.py" fi # ---- systemd ---- step "Copying systemd unit" UNITS_CHANGED=0 install_if_changed "$REPO_DIR/etc/systemd/system/tesm-license.service" /etc/systemd/system/tesm-license.service 644 && UNITS_CHANGED=1 print_status "Unit copied" # ---- nginx ---- step "Configuring nginx reverse proxy" if [ ! -f /etc/nginx/sites-available/tesm-license ]; then sudo cp "$REPO_DIR/etc/nginx/sites-available/tesm-license" /etc/nginx/sites-available/tesm-license fi sudo ln -sf /etc/nginx/sites-available/tesm-license /etc/nginx/sites-enabled/tesm-license sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t >>/var/log/tesm-license-install.log 2>&1 && sudo systemctl reload nginx print_status "nginx configured" # ---- Dienst aktivieren ---- step "Enabling service" if [ "$UNITS_CHANGED" -eq 1 ]; then sudo systemctl daemon-reload fi sudo systemctl enable --now tesm-license.service print_status "Service enabled and started" # ---- Sicherheitsnetz prüfen ---- if [ "$NEEDS_MIGRATION_GUARD" -eq 1 ]; then step "Verifying migrated installation" HEALTHY=0 for i in $(seq 1 15); do sleep 2 if curl -fsS -o /dev/null http://127.0.0.1:5000/login 2>/dev/null; then HEALTHY=1 break fi done if [ "$HEALTHY" -eq 1 ]; then print_status "Migration verified healthy" rm -rf "$BACKUP_DIR" echo -e "${GREEN}✔${NC} Update erfolgreich -- Backup wieder entfernt." else echo -e "${RED}✖ Update fehlgeschlagen -- Dienst antwortet nicht gesund. Rolle zurück...${NC}" sudo systemctl stop tesm-license.service 2>/dev/null || true FAILED_DIR="/srv/tesm-license-failed-update-$(date +%Y%m%d-%H%M%S)" sudo mv /srv/tesm-license "$FAILED_DIR" sudo cp -a "$BACKUP_DIR" /srv/tesm-license sudo systemctl start tesm-license.service echo -e "${YELLOW}Zurückgerollt auf den Stand vor dem Update.${NC}" echo "Backup bleibt erhalten unter: ${BACKUP_DIR}" echo "Die fehlgeschlagene Installation liegt zur Fehlersuche unter: ${FAILED_DIR}" echo "Bitte /var/log/tesm-license/app.log dort prüfen, bevor erneut aktualisiert wird." fi fi echo -e "${GREEN}✔${NC} Installation abgeschlossen. Web-App erreichbar auf Port 80 (nginx) bzw. 5000 (Flask direkt)."