Fortgeschritten 22 minDocker

Ein LLM mit Docker in Produktion bereitstellen Compose

Ein LLM lokal auf dem eigenen Rechner zum Laufen zu bringen, dauert zehn Minuten. Ein LLM mit Docker Compose für ein Team in den Produktionsbetrieb zu bringen — mit einer HTTPS-URL, Monitoring, Backups und echter Sicherheit — ist eine andere Aufgabe. Dieser Leitfaden stellt einen vollständigen Stack (Ollama, Open WebUI, Qdrant, n8n, Traefik) in einer einzigen kommentierten Datei docker-compose.yml zusammen, die auf einem VPS oder einem On-Premises-Server eingesetzt werden kann.

Von Mohamed Meguedmi·Aktualisierung 2026-08-27·Unter Windows, macOS und Linux getestet

#Warum dieser Stack

Ziel ist es, die vier konkreten Anforderungen eines kleinen oder mittleren Unternehmens oder eines technischen Teams abzudecken, das lokale KI einsetzt: eine Inferenz-Engine (Ollama), eine webbasierte Benutzeroberfläche (Open WebUI), eine Vektordatenbank für RAG (Qdrant) und eine No-Code-Automatisierungsschicht (n8n). Traefik wird dem gesamten System als Reverse-Proxy vorgeschaltet und übernimmt HTTPS über Let's Encrypt sowie das Routing.

Jeder Dienst läuft in seinem eigenen isolierten Container mit persistenten Volumes. Sie können einen Dienst deaktivieren, ohne die anderen zu beeinträchtigen, eine einzelne Komponente aktualisieren oder den Stack mit einem einzigen Befehl in einer Staging-Umgebung replizieren.

i
Was dieser Leitfaden nicht ist
Dies ist kein Kubernetes-Leitfaden. Für ein Team von 10–50 Personen auf einem einzigen Server (bis zu etwa 10 gleichzeitige Nutzer auf einer GPU) reicht Docker Compose völlig aus. Für größere Installationen oder für Hochverfügbarkeit über mehrere Knoten hinweg sollten Sie sich k3s oder Nomad ansehen.

#Zielarchitektur

Das Kit Lokale Agenten

Agenten, die auf Ihrem Rechner handeln: agentisches Cline, MCP, n8n + Ollama und lokale Automatisierungen.

  • Lebenslanger Online-Zugang
  • PDF + Dateien
  • Lebenslange Updates
Traefik (Port 80/443)
Reverse-Proxy mit automatischer TLS-Terminierung über Let's Encrypt. Der gesamte externe Datenverkehr läuft über ihn.
Open WebUI (intern)
Chat-Interface vom Typ ChatGPT, verfügbar unter chat.votre-domaine.fr. Lokale Authentifizierung oder OIDC.
Ollama (intern)
Inferenz-Daemon. NICHT öffentlich zugänglich, ausschließlich über das Docker-Netzwerk erreichbar.
Qdrant (intern)
Vektordatenbank für RAG. Speicherung der Embeddings Ihrer Dokumente.
n8n
No-Code-Automatisierung, erreichbar unter n8n.votre-domaine.fr.
Prometheus + Grafana
Optional, intern für die Überwachung von GPU/CPU/RAM bereitgestellt.

#Voraussetzungen

Ein Linux-Server
Ubuntu 22.04 LTS oder Debian 12, SSH-Zugriff als root, mindestens 16 GB RAM, 200 GB Festplattenspeicher.
Eine NVIDIA-GPU wird empfohlen
RTX 3090 mit 24 GB oder RTX 4090 für einen komfortablen Betrieb von 14B–32B-Modellen, oder RTX 4070 mit 12 GB für 7B-Modelle. Ohne GPU bleiben Sie bei 3B-Modellen, die auf der CPU laufen.
Ein Domainname
Mit DNS-Zugriff zum Erstellen von Subdomains. Für Let's Encrypt unverzichtbar.
Docker Engine + Compose v2
Installation über das offizielle Skript get.docker.com. Das Compose-Plugin ist seit 2022 enthalten.
NVIDIA Container Toolkit
Wenn Sie eine GPU haben, ermöglicht dies Docker, sie den Containern zugänglich zu machen.

#1. Den Server vorbereiten

Ausgangspunkt ist eine frisch installierte Ubuntu-22.04-Umgebung. Drei Dinge sind zu installieren: Docker, das NVIDIA Container Toolkit (bei GPU-Nutzung) und eine sauber konfigurierte Firewall.

Docker-Installation
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker compose version
NVIDIA Container Toolkit
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
Testen, ob Docker die GPU erkennt
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
Minimale UFW-Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP - redir vers HTTPS'
sudo ufw allow 443/tcp comment 'HTTPS Traefik'
sudo ufw enable
!
Machen Sie Ollama niemals direkt von außen erreichbar
Der Port 11434 von Ollama verfügt über keine Authentifizierung. Wenn Sie ihn im Internet öffnen, kann jeder Ihre GPU beanspruchen und Ihre Modelle über die API exfiltrieren. Alle Zugriffe erfolgen über Traefik mit Authentifizierung.

#2. Die kommentierte Datei docker-compose.yml

Erstellen Sie einen Arbeitsordner und die Hauptdatei. Das ist das Herzstück der Bereitstellung — jeder Abschnitt ist kommentiert, damit Sie Anpassungen vornehmen können, ohne alles kaputtzumachen.

Verzeichnisstruktur
mkdir -p /opt/llm-stack/{traefik,ollama,open-webui,qdrant,n8n}
cd /opt/llm-stack
touch docker-compose.yml .env
.env (zu ergänzen)
DOMAIN=votre-domaine.fr
ACME_EMAIL=admin@votre-domaine.fr
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=changez-moi-vraiment
TRAEFIK_DASHBOARD_AUTH=admin:$$apr1$$xxxxxxx  # generé avec htpasswd
docker-compose.yml
name: llm-stack

networks:
  proxy:      # réseau public exposé par Traefik
  internal:   # réseau privé Ollama <-> WebUI <-> Qdrant

volumes:
  ollama_data:
  open_webui_data:
  qdrant_data:
  n8n_data:
  traefik_certs:

services:

  # --- Traefik : reverse proxy + Let's Encrypt automatique ---
  traefik:
    image: traefik:v3.2
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.email=${ACME_EMAIL}
      - --certificatesresolvers.le.acme.storage=/certs/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
      - --api.dashboard=true
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik_certs:/certs
    networks: [proxy]
    labels:
      - traefik.enable=true
      - traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN}`)
      - traefik.http.routers.dashboard.service=api@internal
      - traefik.http.routers.dashboard.entrypoints=websecure
      - traefik.http.routers.dashboard.tls.certresolver=le
      - traefik.http.routers.dashboard.middlewares=dashboard-auth
      - traefik.http.middlewares.dashboard-auth.basicauth.users=${TRAEFIK_DASHBOARD_AUTH}

  # --- Ollama : moteur d'inférence, JAMAIS exposé en public ---
  ollama:
    image: ollama/ollama:latest
    restart: unless-stopped
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0:11434
      - OLLAMA_KEEP_ALIVE=24h
      - OLLAMA_NUM_PARALLEL=2
    networks: [internal]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

  # --- Open WebUI : interface chat, exposée en HTTPS ---
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    restart: unless-stopped
    depends_on: [ollama]
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_AUTH=true
      - ENABLE_SIGNUP=false
    volumes:
      - open_webui_data:/app/backend/data
    networks: [proxy, internal]
    labels:
      - traefik.enable=true
      - traefik.http.routers.chat.rule=Host(`chat.${DOMAIN}`)
      - traefik.http.routers.chat.entrypoints=websecure
      - traefik.http.routers.chat.tls.certresolver=le
      - traefik.http.services.chat.loadbalancer.server.port=8080

  # --- Qdrant : base vectorielle pour le RAG ---
  qdrant:
    image: qdrant/qdrant:latest
    restart: unless-stopped
    volumes:
      - qdrant_data:/qdrant/storage
    networks: [internal]

  # --- n8n : automatisation no-code ---
  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    restart: unless-stopped
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
      - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
      - N8N_HOST=n8n.${DOMAIN}
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.${DOMAIN}/
    volumes:
      - n8n_data:/home/node/.n8n
    networks: [proxy, internal]
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`n8n.${DOMAIN}`)
      - traefik.http.routers.n8n.entrypoints=websecure
      - traefik.http.routers.n8n.tls.certresolver=le
      - traefik.http.services.n8n.loadbalancer.server.port=5678
→
Warum zwei Netzwerke?
Das Netzwerk internal hat keinen Zugriff auf den Reverse-Proxy. Ollama und Qdrant sind die einzigen Dienste darin — ein Angreifer, der über Traefik eindringt, kann ihre APIs nicht direkt erreichen. Open WebUI ist mit beiden Netzwerken verbunden: Es empfängt den öffentlichen Datenverkehr über proxy und kommuniziert mit Ollama über internal.

#3. Traefik und DNS konfigurieren

Bevor Sie docker compose up zum ersten Mal ausführen, erstellen Sie drei DNS-Einträge vom Typ A, die auf die öffentliche IP-Adresse Ihres Servers zeigen:

chat.votre-domaine.fr
Die Benutzeroberfläche Open WebUI.
n8n.votre-domaine.fr
Der Workflow-Editor n8n.
traefik.votre-domaine.fr
Das Traefik-Panel (geschützt durch Basic-Auth).

Erzeugen Sie den Hash für die Basic-Auth-Authentifizierung des Traefik-Dashboards. Achtung: Verdoppeln Sie in der .env-Datei die $-Zeichen (Escaping für docker-compose).

Basic-Auth-Hash
sudo apt install apache2-utils
htpasswd -nb admin VotreMotDePasse | sed -e 's/\$/\$\$/g'
!
Let's Encrypt und Rate Limits
Let's Encrypt begrenzt die Anzahl der Zertifikate auf 50 pro Domain und Woche. Verwenden Sie in der Testphase --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory, um den Staging-Server zu nutzen. Sobald alles funktioniert, stellen Sie diese Einstellung um.

#4. Erster Start und Prüfungen

  1. 01
    Stack starten
    Führen Sie im Verzeichnis /opt/llm-stack docker compose up -d aus. Traefik wird die Let's-Encrypt-Zertifikate innerhalb weniger Sekunden beziehen — verfolgen Sie die Logs.
  2. 02
    Den Zustand der Dienste überprüfen
    docker compose ps doit afficher tous les services en running. Aucun ne doit redémarrer en boucle.
  3. 03
    Ein erstes Modell herunterladen
    docker compose exec ollama ollama pull qwen3.5:9b (6,6 GB, 256k Kontext, der vielseitige Referenztyp mit 8 GB im Jahr 2026). Für ein leistungsstärkeres Modell auf einer 24-GB-GPU: qwen3.8:27b (≈18 GB VRAM, 262k Kontext, Apache-2.0-Lizenz).
  4. 04
    Die Benutzeroberfläche testen
    Öffnen Sie https://chat.votre-domaine.fr. Das zuerst erstellte Konto ist das Administratorkonto. ENABLE_SIGNUP=false blockiert danach alle öffentlichen Registrierungen.
  5. 05
    Prüfen, ob die GPU genutzt wird
    docker compose exec ollama ollama ps : la colonne PROCESSOR doit afficher 100% GPU.
Logs von Traefik in Echtzeit
docker compose logs -f traefik | grep -i acme

#5. Sicherheit verstärken

Ein öffentlich zugänglicher, falsch konfigurierter Stack wird innerhalb einer Stunde gescannt. Hier sind die sechs nicht verhandelbaren Regeln für den produktiven Betrieb eines LLM mit Docker Compose, damit Ihre Bereitstellung nicht in jemandes Suchergebnissen auf shodan.io landet.

Starke und einzigartige Passwörter
Generieren Sie Ihre Secrets mit openssl rand -base64 32. Verwenden Sie niemals das Beispielpasswort aus der .env-Datei.
Öffentliche Registrierung deaktivieren
ENABLE_SIGNUP=false in Open WebUI. Andernfalls kann jeder ein Konto erstellen und Ihre GPU-Ressourcen verbrauchen.
Sicherheitsheader über Traefik-Middleware
Fügen Sie eine Middleware namens secureHeaders mit HSTS, frame-deny und content-type-nosniff hinzu. Drei Zeilen, enorme Wirkung.
Ressourcen pro Container begrenzen
Legen Sie unter deploy.resources.limits die Werte für memory und cpus fest. Das verhindert, dass ein abgestürzter Dienst den gesamten Server lahmlegt.
Container sofern möglich schreibgeschützt
Setzen Sie read_only: true bei Traefik und Qdrant. Tmpfs für die temporären Schreibverzeichnisse.
Monatliche Updates
watchtower automatisiert die Pulls, aber bevorzugen Sie ein Cron-Script mit explizitem Git-Tag, um die Versionen in der Produktion unter Kontrolle zu behalten.
Middleware für Sicherheitsheader
# À ajouter sur le service open-webui en labels:
- traefik.http.routers.chat.middlewares=secure-headers
- traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true
- traefik.http.middlewares.secure-headers.headers.frameDeny=true
- traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.secure-headers.headers.browserXssFilter=true
→
Fail2ban vor Traefik
Um Brute-Force-Angriffe auf das Basic-Auth-Verfahren (Dashboard Traefik, n8n) zu blockieren, installieren Sie fail2ban mit einem Filter, der die Traefik-Logs parsiert. 5 Versuche → 1 Stunde IP-Bann. Konfiguration in 10 Zeilen.

#6. Monitoring Prometheus + Grafana

Drei Kennzahlen, die in der Produktion unbedingt überwacht werden müssen: der verwendete VRAM von Ollama, die Anfragerate Open WebUI und der Zustand der Let's Encrypt-Zertifikate (Traefik zeigt alle Metriken über /metrics an).

Block zum Hinzufügen zu docker-compose.yml
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    networks: [internal]

  nvidia-exporter:
    image: utkuozdemir/nvidia_gpu_exporter:latest
    restart: unless-stopped
    devices: [/dev/nvidiactl, /dev/nvidia0]
    volumes:
      - /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:ro
      - /usr/bin/nvidia-smi:/usr/bin/nvidia-smi:ro
    networks: [internal]

  grafana:
    image: grafana/grafana:latest
    restart: unless-stopped
    volumes:
      - grafana_data:/var/lib/grafana
    networks: [proxy, internal]
    labels:
      - traefik.enable=true
      - traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)
      - traefik.http.routers.grafana.entrypoints=websecure
      - traefik.http.routers.grafana.tls.certresolver=le
      - traefik.http.services.grafana.loadbalancer.server.port=3000
prometheus.yml
global:
  scrape_interval: 15s
scrape_configs:
  - job_name: 'traefik'
    static_configs:
      - targets: ['traefik:8080']
  - job_name: 'nvidia'
    static_configs:
      - targets: ['nvidia-exporter:9835']
  - job_name: 'qdrant'
    static_configs:
      - targets: ['qdrant:6333']

Importieren Sie in Grafana die Dashboards mit den IDs 14574 (NVIDIA GPU Exporter) und 17346 (Traefik v3). In 5 Minuten erhalten Sie einen vollständigen Überblick: VRAM, GPU-Temperaturen, HTTP-Anfrageraten pro Subdomain und P95-Latenzen.

#7. Sicherungen und Aktualisierungen

Fünf Volumes enthalten alle Ihre kritischen Daten: ollama_data (Modelle), open_webui_data (Konten + Gespräche + RAG), qdrant_data (Vektoren), n8n_data (Workflows), traefik_certs (Zertifikate).

/usr/local/bin/backup-llm-stack.sh
#!/bin/bash
set -e
BACKUP_DIR=/var/backups/llm-stack
TS=$(date +%Y%m%d-%H%M)
mkdir -p "$BACKUP_DIR"

for vol in open_webui_data qdrant_data n8n_data traefik_certs; do
  docker run --rm \
    -v llm-stack_${vol}:/data \
    -v "$BACKUP_DIR":/backup \
    alpine tar czf "/backup/${vol}-${TS}.tar.gz" -C /data .
done

find "$BACKUP_DIR" -name '*.tar.gz' -mtime +30 -delete
Täglicher Cron um 3 Uhr morgens
sudo chmod +x /usr/local/bin/backup-llm-stack.sh
echo "0 3 * * * root /usr/local/bin/backup-llm-stack.sh" | sudo tee /etc/cron.d/llm-stack-backup
i
Warum ollama_data nicht gesichert wird
Modelle belegen schnell mehrere Dutzend GB und lassen sich mit ollama pull erneut herunterladen. Es ist unnötig, sie in tägliche Backups aufzunehmen – sichern Sie stattdessen die Liste: docker compose exec ollama ollama list > models.txt.

Gehen Sie bei Updates auf Nummer sicher: Legen Sie die Versionen fest (image: ollama/ollama:0.5.4 statt :latest), erstellen Sie vor jedem Update einen Snapshot des VPS und testen Sie zuerst in einer Staging-Umgebung.

Saubere Aktualisierung
cd /opt/llm-stack
docker compose pull
docker compose up -d
docker image prune -f

#Fehlerbehebung

Traefik erzeugt kein Zertifikat
Stellen Sie sicher, dass die Ports 80 und 443 offen sind UND dass der DNS korrekt auf den Server zeigt. docker compose logs traefik | grep -i error zeigt 90 % der Fälle (DNS nicht propagiert, Rate Limit, Challenge fehlgeschlagen).
Open WebUI zeigt 'No models found'
Sie haben in Ollama noch kein Modell heruntergeladen. docker compose exec ollama ollama pull qwen3.5:9b. Prüfen Sie auch OLLAMA_BASE_URL=http://ollama:11434 (Name des Dienstes, nicht localhost).
GPU wird im Container nicht erkannt
nvidia-container-toolkit ist nicht installiert oder Docker wurde nach der Konfiguration nicht neu gestartet. Testen Sie mit docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi.
n8n leitet in einer Schleife auf HTTP um
WEBHOOK_URL und N8N_PROTOCOL=https müssen gesetzt sein. Andernfalls geht n8n davon aus, dass es über HTTP läuft, und der Browser kommt durcheinander.
Grafana ist hinter Traefik nicht erreichbar
Fügen Sie GF_SERVER_ROOT_URL=https://grafana.${DOMAIN} und GF_SERVER_SERVE_FROM_SUB_PATH=false zu seinem environment-Abschnitt hinzu.
Stark steigende Latenz bei mehreren Benutzern
OLLAMA_NUM_PARALLEL ist für den verfügbaren VRAM zu hoch eingestellt. Senken Sie den Wert je nach Grafikkarte auf 1 oder 2. Beobachten Sie ollama ps unter Last.

#Weiterführende Informationen

Ihr Stack läuft, wird überwacht und durch Backups gesichert. Drei naheliegende Wege, ihn weiter zu professionalisieren:

Das RAG mit Ihren Dokumenten verbinden
Der Leitfaden zu RAG mit ChromaDB und Mistral lässt sich problemlos auf Qdrant übertragen – dieselbe Logik für Embeddings und Chunking, eine andere Vektordatenbank.
Geschäftliche Workflows automatisieren
Der Leitfaden „Automatisieren mit n8n und Ollama“ beschreibt zehn konkrete Rezepte (E-Mail-Übersetzung, Lead-Klassifizierung, RSS-Zusammenfassung), die direkt Ihren Software-Stack nutzen.
Compliance-Anforderungen abdecken
Der Leitfaden zu lokalen LLMs und der DSGVO erläutert die gesetzlichen Pflichten (Verzeichnis, Aufbewahrungsdauer, Rechte der Nutzer), die für einen Einsatz im Unternehmen zu dokumentieren sind.
Hat Ihnen dieser Guide geholfen?

Haben Sie Feedback, einen Fehler entdeckt oder möchten Sie etwas präzisieren? Geben Sie uns Bescheid – so wird der Guide für alle besser.