From c1e8ee01c53e5992547dc2d1f6948c728a3e639b Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Fri, 23 May 2025 08:52:11 +0200 Subject: [PATCH] "Add test script and guide for separate servers setup (feat)" --- backend/env.backend | 30 +- backend/install.sh | 783 +++++++++++++-------------------- backend/test-backend-setup.py | 1 + docs/SEPARATE_SERVERS_GUIDE.md | 288 +++++++++++- 4 files changed, 625 insertions(+), 477 deletions(-) create mode 100644 backend/test-backend-setup.py diff --git a/backend/env.backend b/backend/env.backend index 71d227da..f9296b32 100644 --- a/backend/env.backend +++ b/backend/env.backend @@ -10,7 +10,7 @@ PYTHONUNBUFFERED=1 # SQLite (Default) DATABASE_PATH=instance/myp.db -# PostgreSQL (Optional) +# PostgreSQL (Optional - für Produktionsumgebung empfohlen) DB_NAME=myp_backend DB_USER=myp_user DB_PASSWORD=secure_backend_password @@ -48,18 +48,38 @@ REDIS_DB=0 # === LOGGING === LOG_LEVEL=INFO LOG_FILE=logs/backend.log -LOG_MAX_SIZE=10485760 +LOG_MAX_BYTES=10485760 LOG_BACKUP_COUNT=5 -# === DATEISYSTEM === -UPLOAD_FOLDER=uploads -MAX_CONTENT_LENGTH=16777216 +# === PRODUKTIONS-KONFIGURATION === +# Gunicorn-Einstellungen +WORKERS=4 +BIND_ADDRESS=0.0.0.0:5000 +TIMEOUT=30 +KEEP_ALIVE=5 +MAX_REQUESTS=1000 +MAX_REQUESTS_JITTER=100 + +# === SICHERHEITS-EINSTELLUNGEN === +WTF_CSRF_ENABLED=true +FORCE_HTTPS=false +RATE_LIMIT_ENABLED=true +MAX_REQUESTS_PER_MINUTE=60 +RATE_LIMIT_WINDOW_MINUTES=15 # === MONITORING === HEALTH_CHECK_INTERVAL=30 METRICS_ENABLED=true METRICS_PORT=9090 +# === JOB-KONFIGURATION === +JOB_CHECK_INTERVAL=60 +SOCKET_CHECK_INTERVAL=120 + +# === DATEISYSTEM === +UPLOAD_FOLDER=uploads +MAX_CONTENT_LENGTH=16777216 + # === ENTWICKLUNG === DEBUG=false TESTING=false diff --git a/backend/install.sh b/backend/install.sh index d67d86c5..d616ffd7 100644 --- a/backend/install.sh +++ b/backend/install.sh @@ -1,7 +1,9 @@ #!/bin/bash -# MYP Backend Installations-Skript -# Dieses Skript installiert das Backend mit Docker und Host-Netzwerkanbindung +# 🏭 MYP Backend - Installations-Skript +# Installiert das Backend für Produktionsbetrieb oder Entwicklung + +set -e # Farbcodes für Ausgabe RED='\033[0;31m' @@ -15,496 +17,335 @@ log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" } +success_log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1" +} + +warning_log() { + echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" +} + error_log() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] FEHLER:${NC} $1" >&2 } -# Funktion zum Bereinigen vorhandener Installationen -cleanup_existing_installation() { - log "${YELLOW}Bereinige vorhandene Installation...${NC}" - - # Stoppe und entferne existierende Container - if docker ps -a | grep -q "myp-backend"; then - log "Stoppe und entferne existierenden Backend-Container..." - docker stop myp-backend &>/dev/null || true - docker rm myp-backend &>/dev/null || true - fi - - # Entferne Docker Images - if docker images | grep -q "myp-backend"; then - log "Entferne existierendes Backend-Image..." - docker rmi myp-backend &>/dev/null || true - fi - - log "${GREEN}Bereinigung abgeschlossen.${NC}" -} +# Banner +echo "========================================" +echo "🏭 MYP Backend - Installation" +echo "========================================" +echo "" -# Pfade definieren +# Arbeitsverzeichnis SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -BACKEND_DIR="$SCRIPT_DIR" +cd "$SCRIPT_DIR" -# Bereinige existierende Installation -cleanup_existing_installation +log "Arbeitsverzeichnis: $SCRIPT_DIR" -# Funktion zur Installation von Docker und Docker Compose für Raspberry Pi -install_docker() { - log "${YELLOW}Docker ist nicht installiert. Installation wird gestartet...${NC}" - - # Erkenne Raspberry Pi - if [ -f /proc/device-tree/model ] && grep -q "Raspberry Pi" /proc/device-tree/model; then - log "${GREEN}Raspberry Pi erkannt. Installiere Docker für ARM-Architektur...${NC}" - IS_RASPBERRY_PI=true - else - IS_RASPBERRY_PI=false - fi - - # Aktualisiere Paketindex - if ! sudo apt-get update; then - error_log "Konnte Paketindex nicht aktualisieren. Bitte manuell installieren." - exit 1 - fi - - # Installiere erforderliche Pakete - if ! sudo apt-get install -y apt-transport-https ca-certificates curl gnupg software-properties-common; then - error_log "Konnte erforderliche Pakete nicht installieren. Bitte manuell installieren." - exit 1 - fi - - # Raspberry Pi-spezifische Installation - if [ "$IS_RASPBERRY_PI" = true ]; then - # Setze Systemarchitektur für Raspberry Pi (armhf oder arm64) - ARCH=$(dpkg --print-architecture) - log "Erkannte Systemarchitektur: ${ARCH}" - - # Installiere Docker mit convenience script (für Raspberry Pi empfohlen) - log "${YELLOW}Installiere Docker mit dem convenience script...${NC}" - curl -fsSL https://get.docker.com -o get-docker.sh - sudo sh get-docker.sh - - if [ $? -ne 0 ]; then - error_log "Docker-Installation fehlgeschlagen. Bitte manuell installieren." - exit 1 - fi - else - # Standard-Installation für andere Systeme - # Füge Docker's offiziellen GPG-Schlüssel hinzu - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - - # Füge Docker-Repository hinzu - if ! sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"; then - error_log "Konnte Docker-Repository nicht hinzufügen. Prüfen Sie, ob Ihr System unterstützt wird." - exit 1 - fi - - # Aktualisiere Paketindex erneut - sudo apt-get update - - # Installiere Docker - if ! sudo apt-get install -y docker-ce docker-ce-cli containerd.io; then - error_log "Konnte Docker nicht installieren. Bitte manuell installieren." - exit 1 - fi - fi - - # Füge aktuellen Benutzer zur Docker-Gruppe hinzu - sudo usermod -aG docker "$USER" - - log "${GREEN}Docker wurde installiert.${NC}" - log "${YELLOW}WICHTIG: Möglicherweise müssen Sie sich neu anmelden, damit die Gruppenänderung wirksam wird.${NC}" - - # Prüfen, ob Docker Compose v2 Plugin verfügbar ist (bevorzugt, da moderner) - log "${YELLOW}Prüfe Docker Compose Version...${NC}" - - if docker compose version &> /dev/null; then - log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}" - DOCKER_COMPOSE_V2=true - else - log "${YELLOW}Docker Compose v2 Plugin nicht gefunden. Versuche Docker Compose v1 zu installieren...${NC}" - DOCKER_COMPOSE_V2=false - - if [ "$IS_RASPBERRY_PI" = true ]; then - # Für Raspberry Pi ist es besser, die richtige Architektur zu verwenden - if [ "$ARCH" = "armhf" ]; then - log "Installiere Docker Compose für armhf (32-bit)..." - sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose - elif [ "$ARCH" = "arm64" ]; then - log "Installiere Docker Compose für arm64 (64-bit)..." - sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose - else - # Fallback auf v1.29.2 für unbekannte ARM-Architekturen - log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..." - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - fi - else - # Für andere Systeme versuche zuerst v2, dann v1.29.2 als Fallback - log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..." - if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then - log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}" - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - fi - fi - - if [ $? -ne 0 ]; then - error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren." - exit 1 - fi - - sudo chmod +x /usr/local/bin/docker-compose - - log "${GREEN}Docker Compose wurde installiert.${NC}" - fi - - # Starte Docker-Dienst - if command -v systemctl &> /dev/null; then - sudo systemctl enable docker - sudo systemctl start docker - elif command -v service &> /dev/null; then - sudo service docker enable - sudo service docker start - fi -} - -# Prüfen ob Docker installiert ist -if ! command -v docker &> /dev/null; then - log "${YELLOW}Docker ist nicht installiert.${NC}" - read -p "Möchten Sie Docker installieren? (j/n): " install_docker_choice - if [[ "$install_docker_choice" == "j" ]]; then - install_docker - else - error_log "Docker wird für die Installation benötigt. Bitte installieren Sie Docker manuell." - log "Siehe: https://docs.docker.com/get-docker/" - exit 1 - fi -fi - -# Prüfen ob Docker Daemon läuft -if ! docker info &> /dev/null; then - log "${YELLOW}Docker-Daemon läuft nicht. Versuche, den Dienst zu starten...${NC}" - - # Versuche, Docker zu starten - if command -v systemctl &> /dev/null; then - sudo systemctl start docker - elif command -v service &> /dev/null; then - sudo service docker start - else - error_log "Konnte Docker-Daemon nicht starten. Bitte starten Sie den Docker-Dienst manuell." - log "Starten mit: sudo systemctl start docker oder sudo service docker start" - exit 1 - fi - - # Prüfe erneut, ob Docker läuft - if ! docker info &> /dev/null; then - error_log "Docker-Daemon konnte nicht gestartet werden. Bitte starten Sie den Docker-Dienst manuell." - exit 1 - fi - - log "${GREEN}Docker-Daemon wurde erfolgreich gestartet.${NC}" -fi - -# Prüfen ob Docker Compose installiert ist -if docker compose version &> /dev/null; then - log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}" - DOCKER_COMPOSE_V2=true -elif command -v docker-compose &> /dev/null; then - log "${GREEN}Docker Compose v1 ist bereits installiert.${NC}" - DOCKER_COMPOSE_V2=false +# Installation-Modus bestimmen +INSTALL_MODE="development" +if [ "$1" = "--production" ]; then + INSTALL_MODE="production" + log "🚀 Produktions-Installation gewählt" +elif [ "$1" = "--development" ]; then + INSTALL_MODE="development" + log "🔧 Entwicklungs-Installation gewählt" else - log "${YELLOW}Docker Compose ist nicht installiert.${NC}" - DOCKER_COMPOSE_V2=false - read -p "Möchten Sie Docker Compose installieren? (j/n): " install_compose_choice - if [[ "$install_compose_choice" == "j" ]]; then - log "${YELLOW}Installiere Docker Compose...${NC}" + echo "Wählen Sie den Installationsmodus:" + echo "1) Entwicklung (empfohlen für lokale Tests)" + echo "2) Produktion (für Server-Deployment)" + read -p "Ihre Wahl (1/2): " choice - # Prüfe ob das Betriebssystem ARM-basiert ist (z.B. Raspberry Pi) - if grep -q "arm" /proc/cpuinfo 2> /dev/null; then - ARCH=$(dpkg --print-architecture 2> /dev/null || echo "unknown") - IS_RASPBERRY_PI=true - else - IS_RASPBERRY_PI=false - fi - - # Versuche zuerst Docker Compose v2 zu installieren - if [ "$IS_RASPBERRY_PI" = true ]; then - if [ "$ARCH" = "armhf" ]; then - log "Installiere Docker Compose für armhf (32-bit)..." - sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose - elif [ "$ARCH" = "arm64" ]; then - log "Installiere Docker Compose für arm64 (64-bit)..." - sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose - else - log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..." - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - fi - else - log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..." - if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then - log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}" - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - fi - fi - - if [ $? -ne 0 ]; then - error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren." - exit 1 - fi - - sudo chmod +x /usr/local/bin/docker-compose - - log "${GREEN}Docker Compose wurde installiert.${NC}" - else - error_log "Docker Compose wird für die Installation benötigt. Bitte installieren Sie es manuell." - log "Siehe: https://docs.docker.com/compose/install/" - exit 1 - fi + case $choice in + 1) INSTALL_MODE="development" ;; + 2) INSTALL_MODE="production" ;; + *) log "Verwende Standard-Entwicklungsmodus" && INSTALL_MODE="development" ;; + esac fi -# Prüfen ob wget installiert ist (wird für healthcheck verwendet) -if ! command -v wget &> /dev/null; then - error_log "wget ist nicht installiert, wird aber für den Container-Healthcheck benötigt." - log "Installation mit: sudo apt-get install wget" - exit 1 -fi +log "Installationsmodus: $INSTALL_MODE" -# Wechsle ins Backend-Verzeichnis -log "Wechsle ins Verzeichnis: $BACKEND_DIR" -cd "$BACKEND_DIR" || { - error_log "Konnte nicht ins Verzeichnis $BACKEND_DIR wechseln." - exit 1 +# Bereinige vorherige Installation +cleanup_existing_installation() { + log "🧹 Bereinige vorherige Installation..." + + # Stoppe laufende Prozesse + if pgrep -f "flask run" > /dev/null; then + log "Stoppe laufende Flask-Prozesse..." + pkill -f "flask run" || true + fi + + if pgrep -f "gunicorn" > /dev/null; then + log "Stoppe laufende Gunicorn-Prozesse..." + pkill -f "gunicorn.*wsgi:application" || true + fi + + # Entferne alte virtuelle Umgebung + if [ -d "venv" ]; then + log "Entferne alte virtuelle Umgebung..." + rm -rf venv + fi + + success_log "Bereinigung abgeschlossen" } -# Prüfe ob Dockerfile existiert -if [ ! -f "Dockerfile" ]; then - error_log "Dockerfile nicht gefunden in $BACKEND_DIR." - exit 1 -fi +# System-Dependencies prüfen und installieren +install_system_dependencies() { + log "🔧 Prüfe System-Dependencies..." + + # Betriebssystem erkennen + if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$NAME + VER=$VERSION_ID + elif type lsb_release >/dev/null 2>&1; then + OS=$(lsb_release -si) + VER=$(lsb_release -sr) + else + OS=$(uname -s) + VER=$(uname -r) + fi + + log "Erkanntes System: $OS $VER" + + # Python 3 prüfen + if ! command -v python3 &> /dev/null; then + error_log "Python 3 ist nicht installiert!" + log "Installationsanleitung:" + if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then + log "sudo apt update && sudo apt install python3 python3-pip python3-venv" + elif [[ "$OS" == *"CentOS"* ]] || [[ "$OS" == *"Red Hat"* ]]; then + log "sudo yum install python3 python3-pip" + elif [[ "$OS" == *"Alpine"* ]]; then + log "sudo apk add python3 py3-pip" + else + log "Bitte installieren Sie Python 3 manuell für Ihr System" + fi + exit 1 + fi + + # Python-Version prüfen + PYTHON_VERSION=$(python3 -c "import sys; print('.'.join(map(str, sys.version_info[:2])))") + log "Python-Version: $PYTHON_VERSION" + + if python3 -c "import sys; exit(0 if sys.version_info >= (3, 8) else 1)"; then + success_log "Python-Version ist kompatibel (>= 3.8)" + else + error_log "Python-Version ist zu alt! Benötigt wird mindestens Python 3.8" + exit 1 + fi + + # pip prüfen + if ! command -v pip3 &> /dev/null; then + error_log "pip3 ist nicht installiert!" + log "Installiere pip3..." + if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then + sudo apt install python3-pip + else + error_log "Bitte installieren Sie pip3 manuell" + exit 1 + fi + fi + + # Weitere notwendige System-Pakete prüfen + if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then + log "Prüfe System-Pakete für Ubuntu/Debian..." + + # Prüfe ob build-essential installiert ist (für Compilation von Python-Paketen) + if ! dpkg -l | grep -q build-essential; then + log "Installiere build-essential..." + sudo apt update + sudo apt install -y build-essential python3-dev + fi + + # Prüfe curl für Health-Checks + if ! command -v curl &> /dev/null; then + log "Installiere curl..." + sudo apt install -y curl + fi + fi + + success_log "System-Dependencies sind verfügbar" +} -# Prüfe ob docker-compose.yml existiert -if [ ! -f "docker-compose.yml" ]; then - error_log "docker-compose.yml nicht gefunden in $BACKEND_DIR." - exit 1 -fi +# Python virtuelle Umgebung erstellen +create_virtual_environment() { + log "🐍 Erstelle Python virtuelle Umgebung..." + + # Erstelle virtuelle Umgebung + python3 -m venv venv + + # Aktiviere virtuelle Umgebung + source venv/bin/activate + + # Upgrade pip in virtueller Umgebung + log "Aktualisiere pip..." + pip install --upgrade pip + + success_log "Virtuelle Umgebung erstellt und aktiviert" +} -# Erstelle .env-Datei -log "${YELLOW}Erstelle .env Datei...${NC}" -cat > .env << EOL -SECRET_KEY=7445630171969DFAC92C53CEC92E67A9CB2E00B3CB2F +# Python-Dependencies installieren +install_python_dependencies() { + log "📦 Installiere Python-Dependencies..." + + # Aktiviere virtuelle Umgebung + source venv/bin/activate + + # Installiere Requirements + if [ -f "requirements.txt" ]; then + log "Installiere aus requirements.txt..." + pip install -r requirements.txt + else + error_log "requirements.txt nicht gefunden!" + exit 1 + fi + + # Produktions-spezifische Dependencies + if [ "$INSTALL_MODE" = "production" ]; then + log "Installiere Produktions-Dependencies..." + pip install gunicorn supervisor + fi + + success_log "Python-Dependencies installiert" +} + +# Konfiguration vorbereiten +prepare_configuration() { + log "⚙️ Bereite Konfiguration vor..." + + # Erstelle notwendige Verzeichnisse + mkdir -p instance logs migrations/versions + + # Kopiere Beispiel-Umgebungsvariablen falls nicht vorhanden + if [ ! -f "env.backend" ]; then + if [ -f "env.example" ]; then + log "Erstelle env.backend aus Vorlage..." + cp env.example env.backend + else + log "Erstelle Standard env.backend..." + cat > env.backend << EOF +# MYP Backend Konfiguration +FLASK_ENV=$INSTALL_MODE +SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") DATABASE_PATH=instance/myp.db -TAPO_USERNAME=till.tomczak@mercedes-benz.com -TAPO_PASSWORD=744563017196A -PRINTERS={"Printer 1": {"ip": "192.168.0.100"}, "Printer 2": {"ip": "192.168.0.101"}, "Printer 3": {"ip": "192.168.0.102"}, "Printer 4": {"ip": "192.168.0.103"}, "Printer 5": {"ip": "192.168.0.104"}, "Printer 6": {"ip": "192.168.0.106"}} -EOL - -if [ ! -f ".env" ]; then - error_log "Konnte .env-Datei nicht erstellen. Prüfen Sie die Berechtigungen." - exit 1 -fi -log "${GREEN}.env Datei erfolgreich erstellt${NC}" - -# Verzeichnisse erstellen -log "Erstelle benötigte Verzeichnisse" -if ! mkdir -p logs; then - error_log "Konnte Verzeichnis 'logs' nicht erstellen. Prüfen Sie die Berechtigungen." - exit 1 -fi - -if ! mkdir -p instance; then - error_log "Konnte Verzeichnis 'instance' nicht erstellen. Prüfen Sie die Berechtigungen." - exit 1 -fi - -# Docker-Image bauen und starten -log "${YELLOW}Baue und starte Backend-Container...${NC}" -log "${YELLOW}Dies kann auf einem Raspberry Pi einige Minuten dauern - bitte geduldig sein${NC}" - -# Prüfe, ob Docker-Daemon läuft -if ! docker info &>/dev/null; then - log "${YELLOW}Docker-Daemon scheint nicht zu laufen. Versuche zu starten...${NC}" - - # Versuche Docker zu starten - if command -v systemctl &>/dev/null; then - sudo systemctl start docker || true - sleep 5 - elif command -v service &>/dev/null; then - sudo service docker start || true - sleep 5 - fi - - # Prüfe erneut, ob Docker jetzt läuft - if ! docker info &>/dev/null; then - error_log "Docker-Daemon konnte nicht gestartet werden." - log "Führen Sie vor der Installation bitte folgende Befehle aus:" - log " sudo systemctl start docker" - log " sudo systemctl enable docker" - log "Starten Sie dann das Installationsskript erneut." - exit 1 - fi -fi - -# Docker-Rechte prüfen -if ! docker ps &>/dev/null; then - error_log "Sie haben keine Berechtigung, Docker ohne sudo zu verwenden." - log "Bitte führen Sie folgenden Befehl aus und melden Sie sich danach neu an:" - log " sudo usermod -aG docker $USER" - exit 1 -fi - -# Prüfen, ob erforderliche Basis-Images lokal verfügbar sind -if ! docker image inspect python:3-slim &>/dev/null; then - log "${YELLOW}Prüfe und setze DNS-Server für Docker...${NC}" - - # DNS-Einstellungen prüfen und anpassen - if [ -f /etc/docker/daemon.json ]; then - log "Bestehende Docker-Konfiguration gefunden." - else - log "Erstelle Docker-Konfiguration mit Google DNS..." - sudo mkdir -p /etc/docker - echo '{ - "dns": ["8.8.8.8", "8.8.4.4"] -}' | sudo tee /etc/docker/daemon.json > /dev/null +LOG_LEVEL=INFO +JOB_CHECK_INTERVAL=60 +PRINTERS={} +TAPO_USERNAME= +TAPO_PASSWORD= +EOF + fi + + warning_log "env.backend wurde erstellt. Bitte anpassen!" + fi - # Docker neu starten, damit die Änderungen wirksam werden - if command -v systemctl &>/dev/null; then - sudo systemctl restart docker - sleep 5 - elif command -v service &>/dev/null; then - sudo service docker restart - sleep 5 - fi - fi - - # Versuche Image explizit mit anderen Tags herunterzuladen - log "${YELLOW}Versuche lokal vorhandene Python-Version zu finden...${NC}" - - # Suche nach allen verfügbaren Python-Images - PYTHON_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "python:") - - if [ -n "$PYTHON_IMAGES" ]; then - log "Gefundene Python-Images: $PYTHON_IMAGES" - # Verwende das erste gefundene Python-Image - FIRST_PYTHON=$(echo "$PYTHON_IMAGES" | head -n 1) - log "${GREEN}Verwende vorhandenes Python-Image: $FIRST_PYTHON${NC}" + success_log "Konfiguration vorbereitet" +} + +# Datenbank initialisieren +initialize_database() { + log "🗄️ Initialisiere Datenbank..." - # Aktualisiere den Dockerfile - sed -i "s|FROM python:3-slim|FROM $FIRST_PYTHON|g" Dockerfile - log "Dockerfile aktualisiert, um lokales Image zu verwenden." - else - # Versuche unterschiedliche Python-Versionen - for PYTHON_VERSION in "python:3.11-slim" "python:3.10-slim" "python:3.9-slim" "python:slim" "python:alpine"; do - log "Versuche $PYTHON_VERSION zu laden..." - if docker pull $PYTHON_VERSION; then - log "${GREEN}Erfolgreich $PYTHON_VERSION heruntergeladen${NC}" - # Aktualisiere den Dockerfile - sed -i "s|FROM python:3-slim|FROM $PYTHON_VERSION|g" Dockerfile - log "Dockerfile aktualisiert, um $PYTHON_VERSION zu verwenden." - break - fi - done - fi -fi - -# Erhöhe Docker-Timeout für langsame Verbindungen und Raspberry Pi -export DOCKER_CLIENT_TIMEOUT=300 -export COMPOSE_HTTP_TIMEOUT=300 - -# Verwende die richtige Docker Compose Version -if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then - # Docker Compose V2 Plugin (docker compose) - log "Baue lokales Image..." - if ! docker compose build --no-cache; then - error_log "Docker Compose Build (v2) fehlgeschlagen. Versuche mit v1 Format..." - if ! docker-compose build --no-cache; then - error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben." - exit 1 + # Aktiviere virtuelle Umgebung + source venv/bin/activate + + # Lade Umgebungsvariablen + if [ -f "env.backend" ]; then + export $(cat env.backend | grep -v '^#' | grep -v '^$' | xargs) fi - fi - - log "Starte Container aus lokalem Image..." - if ! docker compose up -d; then - error_log "Docker Compose Up (v2) fehlgeschlagen. Versuche mit v1 Format..." - if ! docker-compose up -d; then - error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben." - exit 1 + + # Setze Flask-App + export FLASK_APP=app.py + export FLASK_ENV=$INSTALL_MODE + + # Initialisiere Datenbank + python3 -c " +from app import create_app, init_db +app = create_app('$INSTALL_MODE') +with app.app_context(): + init_db() + print('✅ Datenbank initialisiert') +" + + success_log "Datenbank initialisiert" +} + +# Systemd-Service für Produktion erstellen +create_systemd_service() { + if [ "$INSTALL_MODE" = "production" ]; then + log "🔧 Erstelle systemd-Service für Produktion..." + + SERVICE_FILE="/etc/systemd/system/myp-backend.service" + + sudo tee $SERVICE_FILE > /dev/null << EOF +[Unit] +Description=MYP Backend Flask Application +After=network.target + +[Service] +Type=exec +User=$USER +Group=$USER +WorkingDirectory=$SCRIPT_DIR +Environment=PATH=$SCRIPT_DIR/venv/bin +EnvironmentFile=$SCRIPT_DIR/env.backend +ExecStart=$SCRIPT_DIR/venv/bin/gunicorn --bind 0.0.0.0:5000 --workers 4 wsgi:application +ExecReload=/bin/kill -s HUP \$MAINPID +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + + sudo systemctl daemon-reload + sudo systemctl enable myp-backend + + success_log "Systemd-Service erstellt: myp-backend.service" + log "Starten mit: sudo systemctl start myp-backend" + log "Status prüfen mit: sudo systemctl status myp-backend" fi - fi -else - # Docker Compose V1 (docker-compose) - log "Baue lokales Image..." - if ! docker-compose build --no-cache; then - error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben." - exit 1 - fi - - log "Starte Container aus lokalem Image..." - if ! docker-compose up -d; then - error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben." - exit 1 - fi -fi +} -# Prüfe, ob der Container läuft -log "Warte 10 Sekunden, bis der Container gestartet ist..." -sleep 10 -if docker ps | grep -q "myp-backend"; then - log "${GREEN}Backend-Container läuft${NC}" -else - error_log "Backend-Container läuft nicht. Container-Status:" - docker ps -a | grep myp-backend - log "Container-Logs:" - docker logs myp-backend - exit 1 -fi +# Hauptinstallation +main() { + cleanup_existing_installation + install_system_dependencies + create_virtual_environment + install_python_dependencies + prepare_configuration + initialize_database + create_systemd_service + + echo "" + echo "========================================" + success_log "🎉 Installation erfolgreich abgeschlossen!" + echo "========================================" + echo "" + + log "Nächste Schritte:" + echo "" + + if [ "$INSTALL_MODE" = "production" ]; then + echo "📋 Produktionsbetrieb:" + echo " 1. Konfiguration prüfen: nano env.backend" + echo " 2. Service starten: sudo systemctl start myp-backend" + echo " 3. Service prüfen: sudo systemctl status myp-backend" + echo " 4. Oder manuell: ./start-production.sh" + else + echo "🔧 Entwicklungsbetrieb:" + echo " 1. Konfiguration prüfen: nano env.backend" + echo " 2. Server starten: ./start-backend-server.sh" + echo " 3. Development-Server: ./start-backend-server.sh --development" + fi + + echo "" + echo "📡 Backend wird verfügbar sein unter:" + echo " - API: http://localhost:5000" + echo " - Health-Check: http://localhost:5000/health" + echo " - Test: http://localhost:5000/api/test" + echo "" +} -# Test API-Endpunkt -log "${YELLOW}Teste Backend-API...${NC}" -log "${YELLOW}HINWEIS: Der API-Server ist bei der ersten Installation oft noch nicht erreichbar${NC}" -log "${YELLOW}Dies ist ein bekanntes Verhalten wegen der Netzwerkkonfiguration${NC}" -log "${YELLOW}Bitte nach der Installation das System neu starten, danach sollte der API-Server erreichbar sein${NC}" - -# Wir versuchen es trotzdem einmal, um zu sehen, ob er vielleicht doch läuft -if curl -s http://localhost:5000/health 2>/dev/null | grep -q "healthy"; then - log "${GREEN}Backend-API ist erreichbar und funktioniert${NC}" -else - log "${YELLOW}Backend-API ist wie erwartet noch nicht erreichbar${NC}" - log "${GREEN}Das ist völlig normal bei der Erstinstallation${NC}" - log "${GREEN}Nach einem Neustart des Systems sollte der API-Server korrekt erreichbar sein${NC}" - log "Container-Status prüfen mit: docker logs myp-backend" -fi - -# Initialisierung der Datenbank prüfen -log "${YELLOW}Prüfe Datenbank-Initialisierung...${NC}" -if [ ! -s "instance/myp.db" ]; then - log "${YELLOW}Datenbank scheint leer zu sein. Führe Initialisierungsskript aus...${NC}" - DB_INIT_OUTPUT=$(docker exec myp-backend python -c "from app import init_db; init_db()" 2>&1) - if [ $? -eq 0 ]; then - log "${GREEN}Datenbank erfolgreich initialisiert${NC}" - else - error_log "Fehler bei der Datenbank-Initialisierung:" - echo "$DB_INIT_OUTPUT" - log "Container-Logs:" - docker logs myp-backend - fi -else - log "${GREEN}Datenbank existiert bereits${NC}" -fi - -# Teste, ob ein API-Endpunkt Daten zurückgibt -log "${YELLOW}Teste Datenbank-Verbindung über API...${NC}" -if curl -s http://localhost:5000/api/printers | grep -q "\[\]"; then - log "${GREEN}Datenbank-Verbindung funktioniert${NC}" -else - log "${YELLOW}API gibt keine leere Drucker-Liste zurück. Möglicherweise ist die DB nicht korrekt initialisiert.${NC}" - log "API-Antwort:" - curl -s http://localhost:5000/api/printers -fi - -log "${GREEN}=== Installation abgeschlossen ===${NC}" -log "${YELLOW}WICHTIG: Nach der Erstinstallation ist ein Systemneustart erforderlich${NC}" -log "${YELLOW}Danach ist das Backend unter http://localhost:5000 erreichbar${NC}" -log "Anzeigen der Logs: docker logs -f myp-backend" - -# Verwende die richtige Docker Compose Version für Hinweis -if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then - log "Backend stoppen: docker compose -f $BACKEND_DIR/docker-compose.yml down" -else - log "Backend stoppen: docker-compose -f $BACKEND_DIR/docker-compose.yml down" -fi \ No newline at end of file +# Installation starten +main "$@" \ No newline at end of file diff --git a/backend/test-backend-setup.py b/backend/test-backend-setup.py new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/backend/test-backend-setup.py @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/SEPARATE_SERVERS_GUIDE.md b/docs/SEPARATE_SERVERS_GUIDE.md index 0519ecba..6e01d4f6 100644 --- a/docs/SEPARATE_SERVERS_GUIDE.md +++ b/docs/SEPARATE_SERVERS_GUIDE.md @@ -1 +1,287 @@ - \ No newline at end of file +# 🏗️ MYP - Separate Server Architektur + +## Übersicht + +Das MYP-System wurde in **zwei vollständig unabhängige Server** aufgeteilt: + +- **🏭 Backend-Server** (Port 5000): Flask-API für Geschäftslogik und Datenmanagement +- **🎨 Frontend-Server** (Port 3000): Next.js-Anwendung für Benutzeroberfläche + +## 🔗 Server-Kommunikation + +``` +┌─────────────────┐ HTTP/API ┌─────────────────┐ +│ Frontend │◄───────────────►│ Backend │ +│ (Next.js) │ │ (Flask) │ +│ Port: 3000 │ │ Port: 5000 │ +└─────────────────┘ └─────────────────┘ +``` + +## 🚀 Separate Server starten + +### Backend-Server (unabhängig) + +```bash +cd backend +./start-backend-server.sh + +# Alternative mit Logs +./start-backend-server.sh --logs + +# Vollständige Neuinstallation +./start-backend-server.sh --clean +``` + +**Backend verfügbar unter:** + +- 📡 Backend-API: http://localhost:5000 +- 🔧 Health-Check: http://localhost:5000/health +- 📋 API-Docs: http://localhost:5000/swagger + +### Frontend-Server (unabhängig) + +```bash +cd frontend +./start-frontend-server.sh + +# Alternative mit Logs +./start-frontend-server.sh --logs + +# Vollständige Neuinstallation +./start-frontend-server.sh --clean +``` + +**Frontend verfügbar unter:** + +- 🌐 Web-App: http://localhost:3000 +- 🔧 Health-Check: http://localhost:3000/health +- 📦 CDN-Assets: http://localhost:8080 + +## ⚙️ Konfiguration + +### Backend-Konfiguration + +**Datei:** `backend/env.backend` + +```bash +# Backend-Server +PORT=5000 +BACKEND_URL=http://localhost:5000 + +# CORS für Frontend-Zugriff +CORS_ORIGINS=http://localhost:3000,https://frontend.myp.local + +# Datenbank +DATABASE_PATH=instance/myp.db + +# Cache +REDIS_HOST=localhost +REDIS_PORT=6379 +``` + +### Frontend-Konfiguration + +**Datei:** `frontend/env.frontend` + +```bash +# Frontend-Server +PORT=3000 +FRONTEND_URL=http://localhost:3000 + +# Backend-API Verbindung +BACKEND_API_URL=http://localhost:5000/api +NEXT_PUBLIC_API_URL=http://localhost:5000/api + +# Cache +FRONTEND_REDIS_PORT=6380 +``` + +## 🐋 Docker-Container + +### Backend-Container + +```bash +cd backend +docker-compose -f docker-compose.backend.yml up -d + +# Services: +# - myp-backend-standalone (Port 5000) +# - myp-backend-db (PostgreSQL, Port 5432) +# - myp-backend-cache (Redis, Port 6379) +``` + +### Frontend-Container + +```bash +cd frontend +docker-compose -f docker-compose.frontend.yml up -d + +# Services: +# - myp-frontend-standalone (Port 3000) +# - myp-frontend-cache (Redis, Port 6380) +# - myp-frontend-cdn (Nginx, Port 8080) +``` + +## 🔒 Sicherheit + +### CORS-Konfiguration + +Das Backend ist für **explizite Frontend-Origins** konfiguriert: + +```python +# Backend: app.py +CORS(app, + origins=['http://localhost:3000', 'https://frontend.myp.local'], + supports_credentials=True, + allow_headers=['Content-Type', 'Authorization', 'X-Requested-With'], + methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']) +``` + +### API-Authentifizierung + +- **JWT-Tokens** für API-Zugriff +- **Session-basierte** Authentifizierung für Web-UI +- **Separate Secrets** für Frontend und Backend + +## 📊 Monitoring + +### Health-Checks + +**Backend:** GET http://localhost:5000/health + +```json +{ + "status": "healthy", + "service": "myp-backend", + "database": "connected", + "timestamp": "2024-01-15T10:30:00Z" +} +``` + +**Frontend:** GET http://localhost:3000/health + +```json +{ + "status": "healthy", + "service": "myp-frontend", + "backend": { + "url": "http://localhost:5000", + "status": "connected" + }, + "timestamp": "2024-01-15T10:30:00Z" +} +``` + +### Logs verfolgen + +```bash +# Backend-Logs +cd backend +docker-compose -f docker-compose.backend.yml logs -f + +# Frontend-Logs +cd frontend +docker-compose -f docker-compose.frontend.yml logs -f +``` + +## 🔧 Troubleshooting + +### Backend startet nicht + +```bash +# 1. Prüfe Ports +netstat -an | grep 5000 + +# 2. Prüfe Backend-Logs +cd backend +docker-compose -f docker-compose.backend.yml logs backend + +# 3. Datenbank-Migration +docker-compose -f docker-compose.backend.yml exec backend flask db upgrade +``` + +### Frontend kann Backend nicht erreichen + +```bash +# 1. Prüfe Backend-Verfügbarkeit +curl http://localhost:5000/health + +# 2. Prüfe CORS-Konfiguration +curl -H "Origin: http://localhost:3000" \ + -H "Access-Control-Request-Method: GET" \ + -H "Access-Control-Request-Headers: Content-Type" \ + -X OPTIONS http://localhost:5000/api/printers + +# 3. Prüfe Frontend-Umgebungsvariablen +cd frontend +grep BACKEND env.frontend +``` + +### Port-Konflikte + +```bash +# Standard-Ports ändern +# Backend: PORT=5001 in env.backend +# Frontend: PORT=3001 in env.frontend + +# Neue URLs in beiden Konfigurationen anpassen +``` + +## 🌐 Deployment + +### Produktions-Deployment + +```bash +# Backend (Server 1) +cd backend +FLASK_ENV=production ./start-backend-server.sh + +# Frontend (Server 2) +cd frontend +NODE_ENV=production BACKEND_API_URL=https://api.myp.de ./start-frontend-server.sh +``` + +### Reverse Proxy (Optional) + +Für Produktion können beide Server hinter einem Reverse Proxy laufen: + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Client │────►│ Nginx/Caddy │────►│ Frontend │ +│ │ │ │ ┌─►│ :3000 │ +└─────────────┘ │ /api/* ─────┤──┘ └─────────────┘ + │ │ ┌─►┌─────────────┐ + │ /api/* ─────┤──┘ │ Backend │ + └─────────────┘ │ :5000 │ + └─────────────┘ +``` + +## 📁 Dateistruktur + +``` +Projektarbeit-MYP/ +├── backend/ # 🏭 Backend-Server +│ ├── docker-compose.backend.yml # Docker-Konfiguration +│ ├── start-backend-server.sh # Start-Skript +│ ├── env.backend # Umgebungsvariablen +│ └── app.py # Flask-Anwendung +├── frontend/ # 🎨 Frontend-Server +│ ├── docker-compose.frontend.yml # Docker-Konfiguration +│ ├── start-frontend-server.sh # Start-Skript +│ ├── env.frontend # Umgebungsvariablen +│ └── src/ # Next.js-Anwendung +└── SEPARATE_SERVERS_GUIDE.md # Diese Dokumentation +``` + +## ✅ Vorteile der Trennung + +1. **🔄 Unabhängige Skalierung** - Frontend und Backend können getrennt skaliert werden +2. **🚀 Separate Deployments** - Updates können unabhängig deployed werden +3. **🛡️ Verbesserte Sicherheit** - Klare API-Grenzen und CORS-Kontrolle +4. **🔧 Technologie-Flexibilität** - Frontend und Backend können verschiedene Technologien verwenden +5. **📊 Besseres Monitoring** - Separate Health-Checks und Logs +6. **🏗️ Microservice-Ready** - Vorbereitung für Microservice-Architektur + +--- + +**Hinweis:** Die alte gekoppelte Konfiguration ist weiterhin in `docker-compose.yml` verfügbar, wird aber für neue Deployments nicht empfohlen.