# Custom Templates - Vollständige Anleitung ## 📋 Inhaltsverzeichnis 1. [Überblick](#überblick) 2. [Template-System Architektur](#template-system-architektur) 3. [Anforderungen an Templates](#anforderungen-an-templates) 4. [Neues Template erstellen](#neues-template-erstellen) 5. [Template-Beispiele](#template-beispiele) 6. [Deployment](#deployment) 7. [Troubleshooting](#troubleshooting) 8. [Best Practices](#best-practices) --- ## Überblick Das Container Spawner System verwendet ein **dynamisches Template-System**, das beliebig viele User-Templates unterstützt: - **Konfigurationsgesteuert**: `install.sh` baut **nur** die in `.env` unter `USER_TEMPLATE_IMAGES` definierten Templates - **Flexible Konfiguration**: Templates werden in `.env` definiert (semikolon-getrennt) - **Metadaten-Driven**: Display-Namen und Beschreibungen kommen aus `templates.json` - **Multi-Container Support**: Jeder User kann beliebig viele Container verschiedener Typen erstellen **Standardtemplates:** - `template-01`: Nginx Basic - Einfacher statischer Webserver - `template-02`: Nginx Advanced - Nginx mit erweiterten Features - `template-next`: Next.js Production - React-App mit Shadcn/UI **Custom Templates hinzufügen:** Beliebig viele eigene Templates erstellen (Python, Node.js, etc.) --- ## Template-System Architektur ### Wie das System funktioniert ``` 1. install.sh liest USER_TEMPLATE_IMAGES aus .env ↓ 2. Parst semikolon-getrennte Template-Liste ↓ 3. Baut NUR die definierten Docker Images ↓ 4. Validiert dass Verzeichnisse & Dockerfiles existieren ↓ 5. Warnt bei ungenutzten oder fehlenden Templates ↓ 6. Backend lädt aktualisierte Template-Liste aus .env ↓ 7. Metadaten werden aus templates.json geladen ↓ 8. Dashboard zeigt verfügbare Templates ↓ 9. User klickt "Erstellen" → Container spawnt ``` ### Dateien im System | Datei/Ordner | Zweck | |--------------|-------| | `user-template-xyz/` | Template-Verzeichnis (Dockerfile + Assets) | | `.env` → `USER_TEMPLATE_IMAGES` | Liste aller verfügbaren Images | | `templates.json` | Metadaten (Display-Name, Beschreibung) | | `config.py` | Lädt Templates dynamisch beim Start | | `container_manager.py` | Spawnt Container aus Templates | ### Template-Namen → Typ-Mapping Das System extrahiert automatisch den Container-Typ aus dem Image-Namen: ```python # Beispiele: 'user-template-01:latest' → Typ: 'template-01' 'user-template-next:latest' → Typ: 'template-next' 'user-template-python:latest' → Typ: 'template-python' 'custom-nginx:v1.0' → Typ: 'custom-nginx' ``` **Regel:** Image-Name ohne `user-` Prefix und ohne Tag (`:latest`) = Container-Typ --- ## Anforderungen an Templates ### Pflicht-Anforderungen Jedes Template **MUSS**: 1. **Port 8080 exposen** (unprivileged, kein root) ```dockerfile EXPOSE 8080 ``` 2. **Webserver auf Port 8080 laufen lassen** - Nginx: `listen 8080;` - Node.js: `app.listen(8080)` - Flask: `app.run(port=8080, host='0.0.0.0')` 3. **Als unprivileged User laufen** (Sicherheit) ```dockerfile USER nginx # oder node, www-data, etc. ``` 4. **HTTP-Server bereitstellen** (Traefik routet HTTP-Traffic) ### Optionale Features Templates **KÖNNEN**: - Datenbank-Container integrieren (via Docker Compose in Template) - Umgebungsvariablen nutzen (via ENV in Dockerfile) - Volume-Mounts für persistente Daten (via docker-compose.yml) - Build-Args für Konfiguration (z.B. `ARG NODE_VERSION=18`) ### Was NICHT funktioniert Templates **KÖNNEN NICHT**: - Andere Ports als 8080 nutzen (Traefik-Konfiguration) - Root-Rechte benötigen (Security Policy) - Direkten Zugriff auf Docker Socket (Isolation) - Andere Container spawnen (nur eigener Container) --- ## Neues Template erstellen ### ⚠️ WICHTIG: .env-Konfiguration **Bevor du ein Template hinzufügst, merke dir:** - Nur Templates die in `.env` → `USER_TEMPLATE_IMAGES` definiert sind, werden gebaut - Ohne `.env`-Eintrag wird `bash install.sh` das Template ignorieren - Daher: `.env` ZUERST aktualisieren, dann Template erstellen ### Schritt 1: Verzeichnis erstellen ```bash cd /path/to/spawner mkdir user-template-myapp cd user-template-myapp ``` **Namenskonvention:** `user-template-` - ``: Eindeutiger Identifier (lowercase, keine Sonderzeichen außer `-`) - Beispiele: `user-template-python`, `user-template-django`, `user-template-flask` ### Schritt 2: Dockerfile erstellen **Basis-Vorlage (Nginx):** ```dockerfile FROM nginx:alpine # Expose Port 8080 (unprivileged) EXPOSE 8080 # Kopiere statische Dateien COPY index.html /usr/share/nginx/html/ # Nginx auf Port 8080 konfigurieren RUN sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/default.conf # Run as unprivileged user USER nginx CMD ["nginx", "-g", "daemon off;"] ``` **Erweiterte Vorlage (Node.js):** ```dockerfile FROM node:18-alpine # Working Directory WORKDIR /app # Install Dependencies COPY package*.json ./ RUN npm ci --only=production # Copy Application Code COPY . . # Expose Port 8080 EXPOSE 8080 # Run as unprivileged user USER node # Start Application CMD ["node", "server.js"] ``` **Wichtig:** Port 8080 ist Pflicht! ### Schritt 3: Template-Assets hinzufügen **Beispiel: Nginx mit statischer index.html** ```bash cat > index.html <<'EOF' Mein Custom Template

Willkommen zu meinem Custom Container!

Dieser Container läuft auf Port 8080.

EOF ``` **Beispiel: Node.js mit server.js** ```bash cat > server.js <<'EOF' const express = require('express'); const app = express(); const PORT = 8080; app.get('/', (req, res) => { res.send('

Node.js Template

Läuft auf Port 8080

'); }); app.listen(PORT, '0.0.0.0', () => { console.log(`Server läuft auf Port ${PORT}`); }); EOF ``` ### Schritt 4: `.env` aktualisieren Öffne die `.env` Datei im Hauptverzeichnis: ```bash nano .env ``` Füge dein Template zur `USER_TEMPLATE_IMAGES` Liste hinzu: ```bash # Vorher: USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest" # Nachher: USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest;user-template-myapp:latest" ``` **Wichtig:** Semikolon-getrennt, keine Leerzeichen, mit `:latest` Tag! ### Schritt 5: `templates.json` aktualisieren Öffne `templates.json`: ```bash nano templates.json ``` Füge Metadaten für dein Template hinzu: ```json { "templates": [ { "type": "template-01", "image": "user-template-01:latest", "display_name": "Nginx Basic", "description": "Einfacher Nginx-Server mit statischen Dateien" }, { "type": "template-02", "image": "user-template-02:latest", "display_name": "Nginx Advanced", "description": "Nginx mit erweiterten Features" }, { "type": "template-next", "image": "user-template-next:latest", "display_name": "Next.js Production", "description": "React-App mit Shadcn/UI" }, { "type": "template-myapp", "image": "user-template-myapp:latest", "display_name": "Meine Custom App", "description": "Mein eigenes Template mit Node.js" } ] } ``` **Felder:** - `type`: Muss mit extrahiertem Typ übereinstimmen (`template-myapp`) - `image`: Vollständiger Image-Name mit Tag - `display_name`: Name im Dashboard (beliebig) - `description`: Kurze Beschreibung für User ### Schritt 6: Template lokal bauen ```bash cd /path/to/spawner docker build -t user-template-myapp:latest user-template-myapp/ ``` **Überprüfung:** ```bash docker images | grep user-template-myapp # Expected: user-template-myapp latest abc123def456 5 seconds ago 150MB ``` ### Schritt 7: Template testen Starte einen Test-Container: ```bash docker run -d -p 8080:8080 --name test-myapp user-template-myapp:latest ``` Teste im Browser: ```bash curl http://localhost:8080 # Expected: HTML-Output deines Templates ``` Cleanup: ```bash docker stop test-myapp docker rm test-myapp ``` ### Schritt 8: Änderungen committen ```bash git add user-template-myapp/ .env templates.json git commit -m "feat: add custom template-myapp" git push ``` --- ## Template-Beispiele ### Beispiel 1: Python Flask Template **Verzeichnisstruktur:** ``` user-template-flask/ ├── Dockerfile ├── requirements.txt └── app.py ``` **Dockerfile:** ```dockerfile FROM python:3.11-slim WORKDIR /app # Install Dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy Application COPY app.py . # Expose Port 8080 EXPOSE 8080 # Run as unprivileged user RUN useradd -m appuser USER appuser # Start Flask CMD ["python", "app.py"] ``` **requirements.txt:** ``` Flask==3.0.0 gunicorn==21.2.0 ``` **app.py:** ```python from flask import Flask app = Flask(__name__) @app.route('/') def home(): return '

Flask Template

Läuft auf Port 8080

' if __name__ == '__main__': app.run(host='0.0.0.0', port=8080) ``` **In `.env` hinzufügen:** ```bash USER_TEMPLATE_IMAGES="...;user-template-flask:latest" ``` **In `templates.json` hinzufügen:** ```json { "type": "template-flask", "image": "user-template-flask:latest", "display_name": "Python Flask", "description": "Flask Web-Framework für Python" } ``` ### Beispiel 2: Static Site Generator (Hugo) **Verzeichnisstruktur:** ``` user-template-hugo/ ├── Dockerfile ├── config.toml └── content/ └── _index.md ``` **Dockerfile:** ```dockerfile FROM klakegg/hugo:alpine AS builder WORKDIR /src COPY . . RUN hugo --minify FROM nginx:alpine # Copy built site COPY --from=builder /src/public /usr/share/nginx/html # Nginx on Port 8080 RUN sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/default.conf EXPOSE 8080 USER nginx CMD ["nginx", "-g", "daemon off;"] ``` **config.toml:** ```toml baseURL = "/" languageCode = "de-de" title = "Hugo Template" theme = "ananke" ``` ### Beispiel 3: Database-Backed Template (Node.js + PostgreSQL) **Hinweis:** Für Multi-Container-Templates (mit DB) nutze `docker-compose.yml` **innerhalb** des Templates. **Verzeichnisstruktur:** ``` user-template-node-db/ ├── Dockerfile ├── docker-compose.yml ├── package.json └── server.js ``` **Dockerfile:** ```dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 8080 USER node CMD ["node", "server.js"] ``` **docker-compose.yml (wird vom Container genutzt):** ```yaml version: '3.8' services: app: build: . ports: - "8080:8080" environment: - DATABASE_URL=postgresql://user:password@db:5432/mydb depends_on: - db db: image: postgres:15-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydb volumes: - db-data:/var/lib/postgresql/data volumes: db-data: ``` **Wichtig:** Spawner erstellt nur den Main-Container. Für Multi-Container nutze einen Wrapper-Script oder starte via `docker-compose` im Container. --- ## Deployment ### Lokale Entwicklung ```bash # 1. Template erstellen mkdir user-template-xyz cd user-template-xyz # ... Dockerfile erstellen ... # 2. .env und templates.json aktualisieren nano ../.env nano ../templates.json # 3. Template bauen docker build -t user-template-xyz:latest . # 4. Spawner neu starten cd .. docker-compose restart spawner # 5. Dashboard öffnen # Template sollte jetzt sichtbar sein ``` ### Production Deployment (Server) **Schritt 1: Code committen** ```bash git add user-template-xyz/ .env templates.json git commit -m "feat: add template-xyz" git push ``` **Schritt 2: Auf Server deployen** ```bash # SSH zum Server ssh user@server # Navigiere zum Spawner-Verzeichnis cd /volume1/docker/spawner # Pull neueste Änderungen git pull # Baue neues Template docker build -t user-template-xyz:latest user-template-xyz/ # Kopiere aktualisierte Config-Dateien in Container docker cp .env spawner:/app/.env docker cp templates.json spawner:/app/templates.json # Restart Spawner (lädt neue Konfiguration) docker-compose restart spawner ``` **Schritt 3: Verifikation** ```bash # Überprüfe ob Template geladen wurde docker-compose logs spawner | grep "template-xyz" # Teste via Debug-API curl -H "X-Debug-Token: " \ "http://localhost:5000/api/admin/debug?action=info" # Dashboard öffnen und neues Template prüfen ``` ### Automatisiertes Deployment (install.sh) Das `install.sh` Script baut **nur die in `.env` unter `USER_TEMPLATE_IMAGES` definierten** Templates: ```bash # Lokale Installation cd /path/to/spawner cp .env.example .env # Falls .env nicht existiert # Optional: nano .env # USER_TEMPLATE_IMAGES anpassen bash install.sh # Baut nur definierte Templates ``` ```bash # Auf Server (mit git pull) ssh user@server cd /volume1/docker/spawner git pull # Neue Templates/Änderungen herunterladen bash install.sh # Baut nur definierte Templates ``` **Was install.sh macht:** 1. Liest `USER_TEMPLATE_IMAGES` aus `.env` 2. Parst semikolon-getrennte Template-Liste 3. Baut Docker Images **nur** für definierte Templates 4. Validiert dass Verzeichnisse und Dockerfiles existieren 5. Warnt bei fehlenden oder ungenutzten Verzeichnissen 6. Startet Services neu 7. Templates erscheinen automatisch im Dashboard **Wichtig:** - Alle in `USER_TEMPLATE_IMAGES` definierten Templates müssen entsprechende Verzeichnisse haben - Verzeichnisse ohne `.env`-Eintrag werden NICHT gebaut - Falls `USER_TEMPLATE_IMAGES` nicht definiert ist, fallback auf alte Logik (baue alle) **Vorteil:** - Schnellere Installation (nur nötige Templates) - Volle Kontrolle über welche Templates verfügbar sind - Keine unnötigen Docker-Builds --- ## Template Build-Prozess (.env-basiert) ### Wie install.sh Templates auswählt Das System nutzt `USER_TEMPLATE_IMAGES` in `.env` um zu bestimmen, welche Templates gebaut werden: ```bash # In .env definiert: USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-next:latest" # Verzeichnisstruktur: user-template-01/Dockerfile ✅ wird gebaut user-template-02/Dockerfile ⏭️ wird NICHT gebaut (nicht in .env) user-template-next/Dockerfile ✅ wird gebaut ``` ### Validation & Fehlerbehandlung `install.sh` prüft automatisch: 1. **Verzeichnis-Existenz:** - ✅ Template in `.env` + Verzeichnis vorhanden → baue - ⚠️ Template in `.env` + Verzeichnis fehlt → Warnung, überspringe 2. **Dockerfile-Existenz:** - ✅ Dockerfile vorhanden → baue - ⚠️ Dockerfile fehlt → Warnung, überspringe 3. **Ungekonfigurierte Verzeichnisse:** - ⚠️ Verzeichnis existiert, aber nicht in `USER_TEMPLATE_IMAGES` → Warnung 4. **Build-Fehler:** - ❌ Docker-Build schlägt fehl → Exit mit Fehler ### Beispiel: Teilmenge Templates bauen **Szenario:** Nur Nginx Basic und Next.js bauen (nicht Nginx Advanced) ```bash # 1. Bearbeite .env nano .env # 2. Ändere USER_TEMPLATE_IMAGES: # ALT: USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest" # NEU (nur zwei): USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-next:latest" # 3. Starte install.sh bash install.sh # Output: # Baue Templates aus .env Konfiguration... # [1/2] Baue Template: user-template-01:latest # ✅ user-template-01: OK # [2/2] Baue Template: user-template-next:latest # ✅ user-template-next: OK (kann 2-5 Min dauern) # ✅ 2/2 Template(s) erfolgreich gebaut. # # ⚠️ Ungekonfigurierte Template-Verzeichnisse: # - user-template-02 (nicht in USER_TEMPLATE_IMAGES definiert) ``` ### Fallback bei fehlender Konfiguration Falls `USER_TEMPLATE_IMAGES` nicht definiert ist: ```bash # .env fehlt oder USER_TEMPLATE_IMAGES leer bash install.sh # Output: # ⚠️ USER_TEMPLATE_IMAGES nicht konfiguriert # Fallback: Baue alle user-template-* Verzeichnisse (alte Logik)... # # → Baut alle verfügbaren Templates (Alt-Verhalten für Kompatibilität) ``` --- ## Troubleshooting ### Problem: Template erscheint nicht im Dashboard **Symptom:** Neues Template ist nicht in der Container-Liste sichtbar **Lösung:** ```bash # 1. Überprüfe .env im Container docker exec spawner cat /app/.env | grep USER_TEMPLATE_IMAGES # 2. Überprüfe templates.json im Container docker exec spawner cat /app/templates.json # 3. Überprüfe Backend-Logs docker-compose logs spawner | grep -i template # 4. Falls nicht aktualisiert, kopiere Dateien manuell: docker cp .env spawner:/app/.env docker cp templates.json spawner:/app/templates.json docker-compose restart spawner ``` ### Problem: Container spawnt nicht / Fehler beim Start **Symptom:** Klick auf "Erstellen" → Fehler "Container konnte nicht erstellt werden" **Lösung:** ```bash # 1. Überprüfe ob Image existiert docker images | grep user-template-xyz # 2. Falls nicht vorhanden, baue neu: docker build -t user-template-xyz:latest user-template-xyz/ # 3. Teste Image manuell docker run -d -p 8080:8080 --name test-xyz user-template-xyz:latest # 4. Überprüfe Logs docker logs test-xyz # 5. Cleanup docker stop test-xyz && docker rm test-xyz # 6. Überprüfe Spawner-Logs docker-compose logs spawner | tail -50 ``` ### Problem: Port 8080 nicht erreichbar **Symptom:** Container läuft, aber `curl http://localhost:8080` gibt Timeout **Lösung:** ```bash # 1. Überprüfe ob Container wirklich auf 8080 hört docker exec netstat -tlnp | grep 8080 # 2. Überprüfe Dockerfile cat user-template-xyz/Dockerfile | grep EXPOSE # Expected: EXPOSE 8080 # 3. Überprüfe Webserver-Konfiguration # Nginx: listen 8080; # Node.js: app.listen(8080, '0.0.0.0') # Flask: app.run(port=8080, host='0.0.0.0') # 4. Rebuilde Template mit korrektem Port docker build -t user-template-xyz:latest user-template-xyz/ ``` ### Problem: Traefik routet nicht zum Container **Symptom:** URL öffnet, aber zeigt 404 oder Timeout **Lösung:** ```bash # 1. Überprüfe Container-Labels docker inspect user--- | grep -A10 traefik # 2. Überprüfe Traefik Dashboard # http://:8080 → HTTP Routers # 3. Überprüfe StripPrefix Middleware curl http://localhost:8080/api/http/middlewares | jq . | grep user # 4. Überprüfe Traefik Logs docker-compose logs traefik | grep user- # 5. Starte Traefik neu docker-compose restart traefik ``` ### Problem: Datei-Änderungen werden nicht übernommen **Symptom:** Dockerfile geändert, aber Container nutzt alte Version **Lösung:** ```bash # 1. IMMER --no-cache beim Rebuild verwenden docker build --no-cache -t user-template-xyz:latest user-template-xyz/ # 2. Alte Container entfernen docker ps -a | grep user-template-xyz | awk '{print $1}' | xargs docker rm -f # 3. Neue Container spawnen (via Dashboard oder API) # 4. Überprüfe Image-Erstellungsdatum docker images | grep user-template-xyz # Should show recent timestamp ``` --- ## Best Practices ### Sicherheit 1. **Unprivileged Users verwenden** ```dockerfile # NICHT als root laufen USER nginx # oder node, www-data, appuser, etc. ``` 2. **Minimale Base Images** ```dockerfile # Bevorzuge alpine-Varianten FROM node:18-alpine # statt node:18 FROM python:3.11-slim # statt python:3.11 ``` 3. **Keine Secrets im Image** ```dockerfile # ❌ FALSCH ENV API_KEY=secret123 # ✅ RICHTIG - Via Runtime-Env # Secrets werden vom Spawner injiziert ``` ### Performance 1. **Multi-Stage Builds nutzen** ```dockerfile # Build Stage FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Runtime Stage FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html ``` 2. **Layer Caching optimieren** ```dockerfile # Dependencies zuerst (ändern sich selten) COPY package*.json ./ RUN npm ci # Code danach (ändert sich oft) COPY . . ``` 3. **Image-Größe minimieren** ```dockerfile # Cleanup in einer RUN-Anweisung RUN apt-get update && \ apt-get install -y pkg1 pkg2 && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* ``` ### Wartbarkeit 1. **Versionierung nutzen** ```bash # Statt :latest auch spezifische Versionen taggen docker build -t user-template-xyz:v1.0.0 . docker tag user-template-xyz:v1.0.0 user-template-xyz:latest ``` 2. **README.md pro Template** ```markdown # Template XYZ ## Was macht dieses Template? - Beschreibung - Features - Use Cases ## Konfiguration - Umgebungsvariablen - Volumes - Ports ## Entwicklung - Lokales Setup - Tests - Debugging ``` 3. **Dokumentierte Umgebungsvariablen** ```dockerfile # ENV-Variablen mit Defaults ENV NODE_ENV=production \ PORT=8080 \ LOG_LEVEL=info ``` ### Testing 1. **Health Checks definieren** ```dockerfile HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 ``` 2. **Test-Script erstellen** ```bash #!/bin/bash # test-template.sh IMAGE="user-template-xyz:latest" CONTAINER="test-xyz" # Build docker build -t $IMAGE . # Run docker run -d -p 8080:8080 --name $CONTAINER $IMAGE # Wait sleep 5 # Test curl -f http://localhost:8080 || exit 1 # Cleanup docker stop $CONTAINER && docker rm $CONTAINER echo "✅ Template funktioniert!" ``` 3. **Automatisierte Tests (optional)** ```bash # CI/CD Pipeline (GitHub Actions, GitLab CI) # .github/workflows/test-templates.yml name: Test Templates on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Test Template XYZ run: bash user-template-xyz/test-template.sh ``` --- ## Zusammenfassung ### Schnell-Anleitung ```bash # 0. ZUERST: .env aktualisieren! nano .env # USER_TEMPLATE_IMAGES="...;user-template-myapp:latest" # 1. Verzeichnis erstellen mkdir user-template-myapp # 2. Dockerfile erstellen (Port 8080, unprivileged user) nano user-template-myapp/Dockerfile # 3. Assets hinzufügen (z.B. index.html für Nginx) cp index.html user-template-myapp/ # 4. templates.json aktualisieren nano templates.json # { "type": "template-myapp", "image": "user-template-myapp:latest", ... } # 5. Bauen & Testen (lokal) docker build -t user-template-myapp:latest user-template-myapp/ docker run -d -p 8080:8080 --name test user-template-myapp:latest curl http://localhost:8080 docker stop test && docker rm test # 6. Committen & Pushen git add user-template-myapp/ .env templates.json git commit -m "feat: add template-myapp" git push # 7. Auf Server deployen ssh user@server cd /volume1/docker/spawner # Wichtig: git pull BEVOR install.sh! git pull # install.sh baut automatisch nur die in .env definierten Templates bash install.sh # → Baut user-template-myapp (weil in .env definiert) # 8. Überprüfung docker-compose logs spawner | tail -20 # Dashboard öffnen und Template prüfen ``` ### Checkliste - [ ] Template-Verzeichnis `user-template-/` erstellt - [ ] Dockerfile mit Port 8080 und unprivileged user - [ ] **WICHTIG: `.env` → `USER_TEMPLATE_IMAGES` aktualisiert** (sonst wird Template nicht gebaut!) - [ ] Template lokal gebaut und getestet - [ ] `templates.json` mit Metadaten erweitert - [ ] Änderungen committed und gepusht - [ ] Auf Server deployed: - [ ] `git pull` (holt neue Änderungen) - [ ] `bash install.sh` (baut Templates aus `.env`) - [ ] Überprüfe Logs: `docker-compose logs spawner` - [ ] Dashboard überprüft (Template sichtbar?) - [ ] Container erfolgreich erstellt und erreichbar --- ## Support & Weitere Informationen - **Hauptdokumentation**: `docs/install/DEPLOYMENT_GUIDE.md` - **Architektur**: `CLAUDE.md` - **Troubleshooting**: `docs/install/DEPLOYMENT_GUIDE.md#troubleshooting` - **API-Dokumentation**: `docs/api/` (falls vorhanden) Bei Fragen: Issue auf GitHub/Gitea erstellen oder Admin kontaktieren.