- Updated clear-logs to inform that docker logs cannot be deleted - Updated documentation to reflect docker-based log reading - No log file needed anymore"
20 KiB
Container Spawner - Deployment Guide
🎯 Überblick
Das System unterstützt beliebig viele User-Templates über ein dynamisches Konfigurationssystem:
- Templates werden in
.envdefiniert (semikolon-getrennt) - Metadaten (Namen, Beschreibungen) kommen aus
templates.json install.shbaut automatisch alleuser-template-*Verzeichnisse- Jeder Benutzer kann beliebig viele Container verschiedener Typen erstellen
Standardtemplates (können beliebig erweitert werden):
- template-01: Nginx Basic - Einfacher Nginx-Server mit statischen Dateien
- template-02: Nginx Advanced - Nginx mit erweiterten Features
- template-next: Next.js Production - React-App mit Shadcn/UI
📋 Voraussetzungen
- Docker & Docker Compose
- Python 3.11+
- Node.js 18+ (für Frontend)
- Traefik als Reverse Proxy mit Docker Provider
🚀 Deployment-Anleitung
Phase 1: Vorbereitung (15 Minuten)
1.1 Code auschecken
git pull origin main
1.2 Alte Daten bereinigen (CLEAN SLATE)
# Alle alten User-Container stoppen
docker ps -a | grep "user-" | awk '{print $1}' | xargs docker rm -f 2>/dev/null || true
# Alte Datenbank löschen
rm -f spawner.db
# Logs löschen
rm -rf logs/*
1.3 Templates werden automatisch gebaut!
# install.sh erkennt AUTOMATISCH alle user-template-* Verzeichnisse und baut sie:
# - user-template-01/
# - user-template-02/
# - user-template-next/
# etc.
# Überprüfung der verfügbaren Template-Verzeichnisse:
ls -d user-template*
# Expected output:
# user-template-01 user-template-02 user-template-next
WICHTIG: Das install.sh-Script baut automatisch alle Templates - keine manuellen Docker-Builds nötig!
1.4 Environment konfigurieren
# Copy beispiel Datei
cp .env.example .env
# Bearbeite .env und passe an:
nano .env
Erforderliche Änderungen in .env:
# Pflichtfelder
SECRET_KEY=<generiert mit: python3 -c "import secrets; print(secrets.token_hex(32))">
BASE_DOMAIN=yourdomain.com
SPAWNER_SUBDOMAIN=coder
TRAEFIK_NETWORK=web
TRAEFIK_CERTRESOLVER=lets-encrypt
TRAEFIK_ENTRYPOINT=websecure
# Dynamische Template-Konfiguration (Semikolon-getrennt)
# Liste aller verfügbaren Container-Images
# Metadaten (Namen, Beschreibungen) werden aus templates.json geladen
USER_TEMPLATE_IMAGES=user-template-01:latest;user-template-02:latest;user-template-next:latest
# Optional: SMTP für Magic Links
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASSWORD=password
SMTP_FROM=noreply@example.com
FRONTEND_URL=https://coder.yourdomain.com
Hinweis: Behalte alle anderen Einstellungen aus .env.example (CORS, JWT, etc.)
Phase 2: Services starten (10 Minuten)
2.1 Docker Compose starten
docker-compose up -d --build
# Warte bis Services bereit sind
sleep 10
# Überprüfe Status
docker-compose ps
Erwartet Output:
NAME STATUS PORTS
spawner Up X seconds 5000/tcp
frontend Up X seconds 3000/tcp
traefik Up X seconds 80/tcp, 443/tcp, 8080/tcp
2.2 Logs prüfen
# Backend Logs
docker-compose logs spawner | tail -20
# Frontend Logs
docker-compose logs frontend | tail -20
# Traefik Logs
docker-compose logs traefik | tail -20
Wichtig: Suche nach ERROR-Meldungen. Häufige Fehler:
docker.errors.ImageNotFound: Template-Images nicht gebautConnectionRefusedError: Backend nicht erreichbarCORS error: CORS_ORIGINS nicht konfiguriert
2.3 Health Check
# Backend Health
curl -s http://localhost:5000/health | jq .
# Frontend (falls lokal erreichbar)
curl -s http://localhost:3000 | head -20
Phase 3: Erste Registrierung (5 Minuten)
3.1 Öffne Dashboard
https://coder.yourdomain.com
3.2 Registrierung
- Klick auf "Registrieren"
- Gib Email-Adresse ein:
test@yourdomain.com - Klick "Magic Link senden"
- Überprüfe Email (oder Logs für Magic Link Token wenn SMTP nicht konfiguriert)
- Klick auf Magic Link in Email
- Du wirst zum Dashboard weitergeleitet
3.3 Dashboard überprüfen
- N Container-Cards sichtbar (entsprechend USER_TEMPLATE_IMAGES)
- Standardmäßig: template-01, template-02, template-next
- Alle haben Status "Noch nicht erstellt"
- Jede Card zeigt Display-Namen und Beschreibung aus
templates.json - Buttons zeigen "Erstellen & Öffnen"
Phase 4: Teste beide Container (10 Minuten)
4.1 Development Container erstellen
Dashboard: Dev Container Card → Click "Erstellen & Öffnen"
Erwartet:
1. Loading-Spinner erscheint
2. Neuer Browser-Tab öffnet sich
3. URL: https://coder.yourdomain.com/test-dev (mit deinem slug)
4. Nginx-Willkommensseite wird angezeigt
4.2 Dashboard aktualisieren
Zurück zum Spawner-Tab
Erwartet:
1. Dev-Container Status = "Läuft"
2. Button ändert sich zu "Service öffnen"
3. Last-Used Timestamp wird angezeigt
4.3 Production Container erstellen
Dashboard: Prod Container Card → Click "Erstellen & Öffnen"
Erwartet:
1. Loading-Spinner erscheint
2. Neuer Browser-Tab öffnet sich
3. URL: https://coder.yourdomain.com/test-prod (mit deinem slug)
4. Next.js Demo-Seite mit Shadcn/UI wird angezeigt
4.4 Beide Containers öffnen
Dashboard: Click "Service öffnen" für Dev-Container
→ Öffnet Dev-Container in bestehendem/neuem Tab
Dashboard: Click "Service öffnen" für Prod-Container
→ Öffnet Prod-Container in bestehendem/neuem Tab
Beide sollten funktionieren, ohne /dev oder /prod in der URL!
🔍 Verification Checklist
Backend
- spawner Container läuft (
docker ps | grep spawner) - Flask Server startet ohne Fehler (
docker-compose logs spawner | grep "Running on") - UserContainer Tabelle existiert (
docker exec spawner sqlite3 /app/data/users.db ".schema user_container") - GET /api/user/containers gibt 2 Containers zurück (mit Status "not_created")
- POST /api/container/launch/dev funktioniert und erstellt Container
Frontend
- Dashboard lädt beide Container-Cards
- API-Calls funktionieren (Browser DevTools → Network Tab)
- Buttons sind nicht disabled
- Loading State erscheint beim Klick
- URLs öffnen sich in neuem Tab
Docker & Traefik
docker ps | grep user-zeigt 2 Container nach Launch- Traefik Dashboard zeigt 2 HTTP Routers (für dev und prod)
- StripPrefix entfernt /{slug}-{type} korrekt
- Beide Containers sind erreichbar ohne /dev oder /prod in der URL
URLs
https://coder.yourdomain.com/{slug}-dev→ Dev-Containerhttps://coder.yourdomain.com/{slug}-prod→ Prod-Container- Keine 404 oder CORS-Fehler in Browser Console
🐛 Troubleshooting
Problem: Container spawnt nicht
Symptom: Klick auf "Erstellen & Öffnen" → Fehler "Container konnte nicht erstellt werden"
Lösung:
# 1. Überprüfe Logs
docker-compose logs spawner | tail -50
# 2. Überprüfe ob Images existieren
docker images | grep user-
# 3. Falls nicht vorhanden, baue neu:
docker build -t user-service-template:latest user-template/
docker build -t user-template-next:latest user-template-next/
# 4. Starte Services neu
docker-compose restart spawner
Problem: URL öffnet nicht / 404 Error
Symptom: Browser zeigt 404 oder Timeout beim Klick "Service öffnen"
Lösung:
# 1. Überprüfe Container läuft
docker ps | grep user-testuser-dev
# 2. Überprüfe Traefik Dashboard
curl http://localhost:8080/api/http/routers | grep user
# 3. Überprüfe Container-Labels
docker inspect user-testuser-dev-1 | grep -A5 "traefik"
# 4. Falls Labels falsch, starte Services neu
docker-compose restart
# 5. Überprüfe Traefik Logs
docker-compose logs traefik | grep user
Problem: StripPrefix funktioniert nicht
Symptom: Container erhält Path mit /{slug}-dev noch darin
Lösung:
# 1. Prüfe Traefik Middleware
curl http://localhost:8080/api/http/middlewares | jq . | grep -A10 "user"
# 2. Container sollte bei / landen, nicht bei /{slug}-dev
curl -H "Host: coder.yourdomain.com" \
"http://localhost:8080/testuser-dev/this/is/a/test"
# Sollte zu Container weitergeleitet werden mit Path: /this/is/a/test
# 3. Falls Problem persistiert, rebuild Traefik
docker-compose down
docker-compose up -d --build traefik
Problem: Magic Link funktioniert nicht
Symptom: Email wird nicht empfangen oder Link funktioniert nicht
Lösung:
# 1. Überprüfe SMTP Konfiguration
docker-compose logs spawner | grep -i smtp
# 2. Falls SMTP nicht konfiguriert, überprüfe Logs für Token
docker-compose logs spawner | grep "Magic Link" | tail -5
# 3. Kopiere Token manuell aus Logs und öffne URL:
# https://coder.yourdomain.com/verify-signup?token=ABC123...
# 4. Zum Testen ohne SMTP:
# Setze SMTP_HOST=localhost im .env
# Tokens werden dann nur in Logs ausgegeben
Problem: Frontend kann nicht mit Backend kommunizieren
Symptom: CORS-Fehler oder "Netzwerkfehler"
Lösung:
# 1. Überprüfe CORS_ORIGINS in Backend
docker exec spawner grep CORS_ORIGINS /app/.env
# 2. Sollte enthalten: https://coder.yourdomain.com (oder http://localhost:3000 in Dev)
# 3. Falls nicht richtig gesetzt:
# Bearbeite .env und setze:
CORS_ORIGINS=https://coder.yourdomain.com
# 4. Restart Backend
docker-compose restart spawner
# 5. Browser Cache löschen und Seite neu laden
📊 Monitoring
Logs überwachen
# Alle Services
docker-compose logs -f
# Nur Backend
docker-compose logs -f spawner
# Traefik
docker-compose logs -f traefik
# Frontend
docker-compose logs -f frontend
Container Status
# Alle Container
docker ps
# Mit Filter
docker ps | grep user-
# Detailed Info
docker inspect user-testuser-dev-1
Traefik Status
# Routers
curl http://localhost:8080/api/http/routers
# Middlewares
curl http://localhost:8080/api/http/middlewares
# Services
curl http://localhost:8080/api/http/services
Datenbank prüfen
# Container-Liste
docker exec spawner sqlite3 /app/data/users.db \
"SELECT id, user_id, container_type, container_id FROM user_container LIMIT 10;"
# User-Liste
docker exec spawner sqlite3 /app/data/users.db \
"SELECT id, email, slug, state FROM user LIMIT 10;"
⚙️ Häufige Konfigurationsänderungen nach Deployment
WICHTIG: Die .env Datei wird als Volume in den Container gemountet. Das bedeutet:
- Änderungen in
.envwerden zur Laufzeit gelesen - Du brauchst kein Docker-Rebuild für Konfigurationsänderungen
- Nur
docker-compose down+docker-compose up -dreicht
SMTP/Email-Anmeldedaten ändern
Falls du die Email-Anmeldedaten später ändern musst (z.B. Passwort aktualisiert):
# 1. Bearbeite .env
nano .env
# Ändere diese Zeilen:
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_USER=deine-email@gmail.com
# SMTP_PASSWORD=neues-passwort
# SMTP_FROM=noreply@domain.com
# 2. Stoppe Container komplett und starte neu
docker-compose down
docker-compose up -d spawner
# 3. Überprüfe ob neue Credentials geladen wurden
docker exec spawner cat /app/.env | grep SMTP_HOST
Hinweis: docker-compose restart spawner reicht auch aus (schneller), aber down/up ist sicherer.
Domain oder Base URL ändern
Falls du die Domain oder Subdomain ändern möchtest:
# 1. Bearbeite .env
nano .env
# Ändere diese Zeilen:
# BASE_DOMAIN=neudomain.com
# SPAWNER_SUBDOMAIN=coder (oder etwas anderes)
# FRONTEND_URL=https://coder.neudomain.com
# 2. Starte Services neu
docker-compose down
docker-compose up -d spawner frontend
# 3. Überprüfe Config (sollte neue Domain zeigen)
docker exec spawner cat /app/.env | grep BASE_DOMAIN
Magic Link Token Expiration ändern
Standardmäßig haben Magic Links 15 Minuten Gültigkeitsdauer. Wenn du das ändern möchtest:
# 1. Bearbeite .env
nano .env
# Ändere diese Zeilen:
# MAGIC_LINK_TOKEN_EXPIRY=900 (in Sekunden, default: 15 Min)
# MAGIC_LINK_RATE_LIMIT=3 (max. 3 Links pro Stunde)
# 2. Starte Backend neu
docker-compose restart spawner
# oder sicherer:
# docker-compose down
# docker-compose up -d spawner
JWT Token Expiration ändern
Standardmäßig verfallen JWT Tokens nach 1 Stunde:
# 1. Bearbeite .env
nano .env
# Ändere diese Zeile:
# JWT_ACCESS_TOKEN_EXPIRES=3600 (in Sekunden)
# 2. Starte Backend neu
docker-compose restart spawner
Container-Resource-Limits ändern
Wenn deine Server-Hardware unterschiedlich ist, passe die Limits an:
# 1. Bearbeite .env
nano .env
# Ändere diese Zeilen:
# DEFAULT_MEMORY_LIMIT=512m (RAM pro Container)
# DEFAULT_CPU_QUOTA=50000 (CPU: 50000 = 0.5 CPU, 100000 = 1 CPU)
# 2. Starte Backend neu
docker-compose restart spawner
# Info: Neue Container verwenden sofort die neuen Limits
# Laufende Container behalten alte Limits (bis Neustart)
Logging Level ändern
# 1. Bearbeite .env
nano .env
# Ändere diese Zeile:
# LOG_LEVEL=INFO (Options: DEBUG, INFO, WARNING, ERROR)
# 2. Starte Backend neu
docker-compose restart spawner
Überprüfe welche Werte der Container tatsächlich nutzt
Falls du unsicher bist, ob die neuen Konfigurationswerte geladen wurden:
# Zeige die .env Werte, die der Container sieht
docker exec spawner cat /app/.env | grep SMTP
# Alle SMTP-Einstellungen anzeigen:
docker exec spawner cat /app/.env | grep SMTP
# Überprüfe mit Python, ob die Werte korrekt geladen sind:
docker exec spawner python3 << 'EOF'
from config import Config
print(f"SMTP_HOST: {Config.SMTP_HOST}")
print(f"SMTP_USER: {Config.SMTP_USER}")
print(f"SMTP_PORT: {Config.SMTP_PORT}")
EOF
Wichtig:
cat /app/.env | grep SMTPzeigt die aktuellen Werte aus der.envDateidocker exec spawner envzeigt Shell-Variablen, nicht Python-Variablen!- Python lädt die Werte mit
load_dotenv()- überprüfe mit Python-Code ob sie korrekt geladen sind
🐛 Debug-API für Administratoren
Neue Feature: Admin-API zum Debuggen und Bereinigen von Logs und Datenbanken
Vorbereitung: DEBUG_TOKEN generieren
# 1. Token generieren
python3 -c "import secrets; print(secrets.token_hex(32))"
# Beispiel-Output:
# a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# 2. In .env eintragen
nano .env
# DEBUG_TOKEN=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# 3. Backend neustarten
docker-compose restart spawner
Debug-API Endpoints
Base: /api/admin/debug
Authentifizierung via Header:
curl -H "X-Debug-Token: your-token-here" "http://localhost:5000/api/admin/debug?action=..."
Oder mit Admin JWT Token:
curl -H "Authorization: Bearer your-jwt-token" "http://localhost:5000/api/admin/debug?action=..."
Verfügbare Actions
1. Logs anzeigen (view-logs)
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=view-logs"
Zeigt die letzten 100 Zeilen der Docker Container Logs (entspricht docker logs spawner --tail 100).
2. Logs löschen (clear-logs)
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=clear-logs"
Docker-Logs können nicht gelöscht werden! Diese Action ist informativ. Um Logs zu löschen, nutze stattdessen:
docker-compose down
docker-compose up -d spawner
Das startet den Container neu und die Logs werden geleert.
3. User entfernen (delete-email)
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=delete-email&email=test@example.com"
Entfernt einen User komplett aus der Datenbank:
- User-Profil gelöscht
- Container gelöscht (falls existiert)
- Alle Token gelöscht
- Alle Datenbank-Einträge entfernt
WARNUNG: Das ist nicht rückgängig zu machen!
4. Magic Link Tokens entfernen (delete-token)
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=delete-token&email=test@example.com"
Löscht nur die Magic Link Tokens für eine Email. Der User bleibt bestehen!
Nützlich wenn:
- Rate-Limiting blockiert den User
- Tokens sind fehlerhaft
- User neue Tokens anfordern soll
5. Hilfe anzeigen (info)
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=info"
Zeigt alle verfügbaren Actions und Beispiele.
Praktische Beispiele
Problem: User kann sich nicht anmelden (Rate Limit)
# 1. Lösche alle Tokens für diese Email
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=delete-token&email=user@example.com"
# 2. User kann jetzt neu anfragen
Problem: Alte Test-User in der Datenbank
# Lösche kompletten User
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=delete-email&email=test@example.com"
Problem: Logs sind zu groß
# Lösche alle Logs
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=clear-logs"
Problem: Brauche die letzten Fehler zum Debuggen
# Hole letzten 100 Zeilen
curl -H "X-Debug-Token: xxx" \
"http://localhost:5000/api/admin/debug?action=view-logs"
Bash-Alias für schnellen Zugriff
Füge dies in ~/.bashrc ein für schnellere Befehle:
export SPAWNER_DEBUG_TOKEN="dein-token-hier"
export SPAWNER_URL="http://localhost:5000"
alias spawner-logs="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=view-logs'"
alias spawner-clear-logs="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=clear-logs'"
alias spawner-delete-email="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=delete-email&email="
Dann:
# Logs anzeigen
spawner-logs
# User löschen
spawner-delete-email=test@example.com"
🔐 Security Checklist
- SECRET_KEY ist generiert und komplex
- JWT_SECRET_KEY ist gesetzt (oder nutzt SECRET_KEY)
- CORS_ORIGINS ist auf richtige Domain gesetzt
- SMTP_PASSWORD ist nicht im .env.example hart-codiert
- Database-URL nutzt keine Standardpasswörter (für Production)
- Traefik Let's Encrypt Email ist gesetzt
- TLS ist aktiviert für alle Routes
- Container-Ressource Limits sind gesetzt (Memory, CPU)
📈 Scaling & Performance
Single User Multiple Containers
- Pro User können 2 Container laufen (dev und prod)
- Jeder Container: 512MB RAM, 0.5 CPU (konfigurierbar)
- Für 100 User: Max 1GB RAM pro Container = 200GB total (nicht realistisch!)
Production Empfehlungen
- Datenbank: Wechsel auf PostgreSQL (in config.py kommentiert)
- Storage: Persistente Volumes für Container-Daten
- Backups: Regelmäßige Backups der Datenbank und User-Volumes
- Monitoring: Prometheus + Grafana für Metrics
- Logging: Centralized Logging (ELK, Loki)
Load Testing
# Einfacher Test mit 10 gleichzeitigen Containern
for i in {1..10}; do
docker run -d \
--network web \
--label "test=true" \
user-service-template:latest
done
# Überwachen
docker stats | grep "test"
# Cleanup
docker ps --filter "label=test=true" | xargs docker rm -f
🎓 Nächste Schritte
Phase 1: MVP Live ✅
- 2 Container-Typen (dev, prod)
- On-Demand Erstellung
- Multi-Container Dashboard
- Status-Tracking
Phase 2: Enhancements (Optional)
- Container-Logs im Dashboard
- Container-Restart pro Type
- Resource-Monitoring
- Container-Cleanup (Idle Timeout)
- Custom Templates vom User
Phase 3: Admin Features (Optional)
- Container-Management im Admin-Panel
- User-Quotas pro Container-Typ
- Template-Updates ohne Service-Restart
- Audit Logging für Container-Events
📞 Support & Dokumentation
Wichtige Dateien
- IMPLEMENTATION_SUMMARY.md - Detaillierte Feature-Liste
- TEST_VERIFICATION.md - Test-Anleitung
- CLAUDE.md - Projekt-Übersicht
- docker-compose.yml - Service-Konfiguration
- .env.example - Environment-Template
Häufig benötigte Commands
# Status überprüfen
docker-compose ps
# Logs anschauen
docker-compose logs -f [service]
# Services neu starten
docker-compose restart [service]
# Container in Python Shell bearbeiten
docker exec -it spawner python
# Datenbank migrieren
docker exec spawner flask db migrate
docker exec spawner flask db upgrade
# Admin-User erstellen
docker exec -it spawner python <<EOF
from app import app, db
from models import User
with app.app_context():
user = User(email='admin@example.com', slug='admin')
user.is_admin = True
user.state = 'verified'
db.session.add(user)
db.session.commit()
EOF
Version: 1.0.0 (MVP) Deployment Date: 2025-01-31 Last Updated: 2025-02-01 Status: ✅ Ready for Production