spawner/docs/guides/custom-templates.md
XPS\Micro 960e69bf62 docs: update custom-templates guide for .env-based template building
- Update overview to clarify that only .env-defined templates are built
- Update architecture diagram to reflect new .env-based process
- Add new 'Template Build-Prozess' section with detailed explanation
- Update 'Automatisiertes Deployment' with correct .env-based instructions
- Add emphasis to WICHTIG notes about .env configuration
- Update quick-start guide to show .env configuration as first step
- Update checklist to highlight critical .env step
- Clarify validation, error handling, and fallback behavior
2026-02-02 16:43:54 +01:00

24 KiB

Custom Templates - Vollständige Anleitung

📋 Inhaltsverzeichnis

  1. Überblick
  2. Template-System Architektur
  3. Anforderungen an Templates
  4. Neues Template erstellen
  5. Template-Beispiele
  6. Deployment
  7. Troubleshooting
  8. 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)
.envUSER_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:

# 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)

    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)

    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 .envUSER_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

cd /path/to/spawner
mkdir user-template-myapp
cd user-template-myapp

Namenskonvention: user-template-<name>

  • <name>: Eindeutiger Identifier (lowercase, keine Sonderzeichen außer -)
  • Beispiele: user-template-python, user-template-django, user-template-flask

Schritt 2: Dockerfile erstellen

Basis-Vorlage (Nginx):

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):

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

cat > index.html <<'EOF'
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Mein Custom Template</title>
</head>
<body>
    <h1>Willkommen zu meinem Custom Container!</h1>
    <p>Dieser Container läuft auf Port 8080.</p>
</body>
</html>
EOF

Beispiel: Node.js mit server.js

cat > server.js <<'EOF'
const express = require('express');
const app = express();
const PORT = 8080;

app.get('/', (req, res) => {
    res.send('<h1>Node.js Template</h1><p>Läuft auf Port 8080</p>');
});

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:

nano .env

Füge dein Template zur USER_TEMPLATE_IMAGES Liste hinzu:

# 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:

nano templates.json

Füge Metadaten für dein Template hinzu:

{
  "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

cd /path/to/spawner
docker build -t user-template-myapp:latest user-template-myapp/

Überprüfung:

docker images | grep user-template-myapp
# Expected: user-template-myapp   latest   abc123def456   5 seconds ago   150MB

Schritt 7: Template testen

Starte einen Test-Container:

docker run -d -p 8080:8080 --name test-myapp user-template-myapp:latest

Teste im Browser:

curl http://localhost:8080
# Expected: HTML-Output deines Templates

Cleanup:

docker stop test-myapp
docker rm test-myapp

Schritt 8: Änderungen committen

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:

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:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return '<h1>Flask Template</h1><p>Läuft auf Port 8080</p>'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

In .env hinzufügen:

USER_TEMPLATE_IMAGES="...;user-template-flask:latest"

In templates.json hinzufügen:

{
  "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:

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:

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:

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):

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

# 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

git add user-template-xyz/ .env templates.json
git commit -m "feat: add template-xyz"
git push

Schritt 2: Auf Server deployen

# 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

# Überprüfe ob Template geladen wurde
docker-compose logs spawner | grep "template-xyz"

# Teste via Debug-API
curl -H "X-Debug-Token: <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:

# 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
# 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:

# 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)

# 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:

# .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:

# 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:

# 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:

# 1. Überprüfe ob Container wirklich auf 8080 hört
docker exec <container-id> 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:

# 1. Überprüfe Container-Labels
docker inspect user-<slug>-<type>-<id> | grep -A10 traefik

# 2. Überprüfe Traefik Dashboard
# http://<server>: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-<slug>

# 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:

# 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

    # NICHT als root laufen
    USER nginx  # oder node, www-data, appuser, etc.
    
  2. Minimale Base Images

    # Bevorzuge alpine-Varianten
    FROM node:18-alpine  # statt node:18
    FROM python:3.11-slim  # statt python:3.11
    
  3. Keine Secrets im Image

    # ❌ FALSCH
    ENV API_KEY=secret123
    
    # ✅ RICHTIG - Via Runtime-Env
    # Secrets werden vom Spawner injiziert
    

Performance

  1. Multi-Stage Builds nutzen

    # 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

    # Dependencies zuerst (ändern sich selten)
    COPY package*.json ./
    RUN npm ci
    
    # Code danach (ändert sich oft)
    COPY . .
    
  3. Image-Größe minimieren

    # 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

    # 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

    # Template XYZ
    
    ## Was macht dieses Template?
    - Beschreibung
    - Features
    - Use Cases
    
    ## Konfiguration
    - Umgebungsvariablen
    - Volumes
    - Ports
    
    ## Entwicklung
    - Lokales Setup
    - Tests
    - Debugging
    
  3. Dokumentierte Umgebungsvariablen

    # ENV-Variablen mit Defaults
    ENV NODE_ENV=production \
        PORT=8080 \
        LOG_LEVEL=info
    

Testing

  1. Health Checks definieren

    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
      CMD curl -f http://localhost:8080/health || exit 1
    
  2. Test-Script erstellen

    #!/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)

    # 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

# 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-<name>/ erstellt
  • Dockerfile mit Port 8080 und unprivileged user
  • WICHTIG: .envUSER_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.