#!/bin/bash # Deploy Antragstracker auf VServer # Usage: ./scripts/deploy.sh [--build-only] [--full] [--skip-frontend] # # Modes: # (default) Build + deploy code, restart container # --build-only Build Docker image on server, don't restart # --full Full deploy: frontend build + code sync + docker rebuild + restart # --skip-frontend Skip local frontend build (use existing build/) # # Voraussetzung: ssh vserver funktioniert set -euo pipefail VSERVER="vserver" REMOTE_DIR="/opt/antragstracker" CONTAINER="antragstracker-hagen" PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" # Parse args BUILD_ONLY=false SKIP_FRONTEND=false for arg in "$@"; do case $arg in --build-only) BUILD_ONLY=true ;; --full) ;; # default behavior --skip-frontend) SKIP_FRONTEND=true ;; -h|--help) echo "Usage: $0 [--build-only] [--full] [--skip-frontend]" exit 0 ;; *) echo "Unknown arg: $arg"; exit 1 ;; esac done cd "$PROJECT_DIR" # 1. Frontend bauen (lokal) if [ "$SKIP_FRONTEND" = false ]; then echo "🔨 Frontend bauen..." cd frontend && npm run build && cd .. echo " ✓ Frontend build fertig ($(du -sh frontend/build | cut -f1))" else echo "⏭️ Frontend-Build übersprungen" fi # 2. Code zum VServer synchronisieren echo "📦 Code synchronisieren..." tar czf /tmp/antragstracker-deploy.tar.gz \ --exclude='.git' \ --exclude='.venv' \ --exclude='venv' \ --exclude='node_modules' \ --exclude='frontend/.svelte-kit' \ --exclude='data' \ --exclude='*.log' \ --exclude='*.pyc' \ --exclude='__pycache__' \ --exclude='.DS_Store' \ --exclude='.pytest_cache' \ --exclude='tracker.db*' \ --exclude='antraege.db' \ --exclude='.github' \ --exclude='logs' \ -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")" scp /tmp/antragstracker-deploy.tar.gz "$VSERVER:/tmp/" ssh "$VSERVER" "cd /opt && tar xzf /tmp/antragstracker-deploy.tar.gz && rm /tmp/antragstracker-deploy.tar.gz" rm -f /tmp/antragstracker-deploy.tar.gz echo " ✓ Code synchronisiert" # 3. Docker Image bauen (auf VServer) echo "🐳 Docker Image bauen auf VServer..." ssh "$VSERVER" "cd $REMOTE_DIR && docker compose build --no-cache" echo " ✓ Image gebaut" if [ "$BUILD_ONLY" = true ]; then echo "⏹️ Build-only Mode — Container wird nicht neu gestartet" exit 0 fi # 4. Container neu starten echo "🔄 Container neu starten..." ssh "$VSERVER" "cd $REMOTE_DIR && docker compose up -d" echo " ✓ Container gestartet" # 5. Warten + Health-Check echo "⏳ Warte auf Startup (5s)..." sleep 5 echo "🏥 Health-Check..." HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://antraege.toppyr.de/api/health" 2>/dev/null || echo "000") if [ "$HTTP_STATUS" = "200" ]; then echo " ✓ Health-Check OK (HTTP $HTTP_STATUS)" elif [ "$HTTP_STATUS" = "000" ]; then sleep 5 HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://antraege.toppyr.de/api/health" 2>/dev/null || echo "000") if [ "$HTTP_STATUS" = "200" ]; then echo " ✓ Health-Check OK (HTTP $HTTP_STATUS, 2. Versuch)" else echo " ⚠️ Health-Check fehlgeschlagen (HTTP $HTTP_STATUS)" echo " Logs prüfen: ssh $VSERVER 'docker logs --tail 20 $CONTAINER'" fi else echo " ⚠️ Health-Check: HTTP $HTTP_STATUS" echo " Logs prüfen: ssh $VSERVER 'docker logs --tail 20 $CONTAINER'" fi echo "" echo "✅ Deploy fertig!" echo " URL: https://antraege.toppyr.de" echo " Logs: ssh $VSERVER 'docker logs --tail 50 $CONTAINER'"