Startseite / Artikel / Ollama und Open WebUI in Docker für ein Team selbst hosten

Ollama und Open WebUI in Docker für ein Team selbst hosten

Ersetze verstreute Ollama-Installationen durch einen Docker-Compose-Stack: internes Ollama, Open WebUI mit Authentifizierung, TLS über Caddy, GPU-Passthrough, Backups und Fehlerbehebung.

1974 Wörter

Lokale KI-Setups beginnen meist mit einer Person, einer Workstation und einem gelungenen Nachmittag. Jemand installiert Ollama, lädt ein Modell, und die Chat-Ausgabe ist großartig. Dann will ein Kollege dasselbe. Die schnelle Lösung: Modelldateien per USB-Stick kopieren, Ollama auf einem zweiten Rechner installieren und notieren, welche Befehle man ausführt. Einen Monat später gibt es vier Maschinen, drei Ollama-Versionen, abweichende Modelldateien und eine geteilte Tabelle, die IP-Adressen Ports zuordnet.

Diese Anordnung hält nicht. Sie verschwendet Speicherplatz, lässt die Konfiguration auseinanderdriften und macht die Person, die den ersten Rechner aufgesetzt hat, still und leise zum unbezahlten Sysadmin eines fragilen Dienstes. Im Folgenden wird sie durch einen containerisierten Stack ersetzt, in dem Ollama in einem internen Netz läuft, Open WebUI die Anmeldung übernimmt und ein Reverse Proxy nach außen zeigt.

Warum Weitergabe von Hand scheitert

Die Probleme zeigen sich meist erst nach einigen Wochen Nutzung.

Doppelter Speicher. Ein 7B-Modell mit Q4-Quantisierung belegt rund 4 GB. Ein 70B-Modell braucht eher 40 GB. Diese Dateien auf jeden Teamrechner zu kopieren, füllt NVMe-Laufwerke und flutet den lokalen Switch.

Versionsdrift. Läuft bei einer Person eine ältere Runtime und bei einer anderen ein neuerer Build, weicht das Verhalten ab. Modelle können ohne Fehlermeldung scheitern, oder zwei Personen erhalten für denselben Prompt unterschiedliche Ausgaben. Debugging wird dann zur Jagd nach Softwareversionen statt nach Ursachen.

Offen im Netz. Das ist das Gefährlichste. Die übliche Abkürzung ist, OLLAMA_HOST=0.0.0.0 zu setzen und Port 11434 in der Firewall zu öffnen. Damit liegt die rohe Ausführungs-API ohne Authentifizierung, Verschlüsselung und Rate Limiting im Netz. Jeder, der die Adresse erreicht, kann nicht vertrauenswürdige Workloads starten, Rechenleistung verbrennen, aktiven Kontext lesen oder gespeicherte Gewichte manipulieren.

Ein containerisiertes Setup beseitigt alle drei Probleme, indem es die Umgebung deklarativ macht. Eine Docker-Compose-Datei wird zur exakten Spezifikation. Modelldaten liegen in eigenen persistenten Volumes, der Netzwerkzugriff ist segmentiert, und der Stack startet auf jedem Linux-Host gleich.

Der Aufbau

Die rohe Modellausführung bleibt von allem getrennt, was Nutzer berühren. Ollama läuft nur innerhalb eines internen Bridge-Netzes. Open WebUI sitzt davor und übernimmt die Authentifizierung. Stell es dir als Schichten von unten nach oben vor:

  • Ein Linux-Host mit NVIDIA-Treiber oder ROCm
  • Ein Docker-Bridge-Netz namens ai_network (172.28.0.0/16)
  • Ein Ollama-Container (die Inferenz-Engine, intern Port 11434, GPU direkt durchgereicht)
  • Ein Open-WebUI-Container (Web-App plus Datenbank, intern Port 8080, Authentifizierung erzwungen)
  • Ein benanntes Volume ollama_models für Ollama und eines namens open_webui_data für Open WebUI
  • Open WebUI nur auf 127.0.0.1:3000 veröffentlicht, davor ein Reverse Proxy (Caddy oder Nginx mit TLS) und dahinter authentifizierte Nutzer

Wofür jedes Teil zuständig ist

Jede Schicht braucht klare Grenzen, bevor irgendetwas verbunden wird.

Ollama ist nur der Backend-Inferenzdienst. Es lädt Gewichte in den Speicher, verteilt Tensoroperationen auf GPU oder CPU und stellt eine HTTP-REST-API bereit. Benutzerverwaltung, Sessions und mandantenfähige Autorisierung hat es bewusst nicht.

Sein Zustand liegt vollständig im Modellspeicher, der über OLLAMA_MODELS festgelegt wird, standardmäßig /root/.ollama im Container. Beim Laden eines Modells landen die Layer direkt in diesem Volume. Weil Ollama sonst nichts speichert, kannst du das Container-Image löschen oder ersetzen, und jedes heruntergeladene Modell bleibt auf der Festplatte.

Open WebUI ist die Web-App und Orchestrierungsschicht, die Menschen tatsächlich nutzen. Sie speichert Zugangsdaten, behält den Chatverlauf, setzt rollenbasierte Berechtigungen durch und führt Retrieval-Augmented-Generation-Pipelines aus. Modellmathematik macht sie selbst nicht. Sie übersetzt Browseraktionen in API-Aufrufe an den internen Ollama-Dienst. Ihr eigener Zustand liegt in einer eingebetteten SQLite-Datenbank und lokalen Dateien im Volume open_webui_data. Geht dieses Volume verloren, schadet das Konten und Gesprächsverlauf, die Modell-Binärdateien bleiben aber unberührt.

Docker liefert Isolation, Netzwerkrichtlinien und einen reproduzierbaren Start. Weil Limits und Volume-Mounts in einem Manifest stehen, bleiben Systemabhängigkeiten unabhängig davon, was im Host-Betriebssystem installiert ist.

Warum keine Desktop-App

Headless-Dienste werden oft mit Desktop-GUI-Tools wie LM Studio verglichen. LM Studio ist eine gute Spielwiese für eine einzelne Person, die Prompts ausprobiert. Es bietet aber keine native Mehrbenutzer-Token-Warteschlange, keine Verwaltung von Hintergrunddiensten und keine modulare Microservice-Integration. Ollama in Docker liefert das Daemon-Verhalten, eine einheitliche API und die saubere Trennung, die ein gemeinsames Deployment braucht.

Hardware auswählen

Die lokale Generierungsgeschwindigkeit hängt vor allem von VRAM-Bandbreite, Breite des Speicherbusses und davon ab, ob das Modell hineinpasst, nicht von FLOPS auf dem Datenblatt. Diese groben Kombinationen sind ein Ausgangspunkt.

  • 7B- bis 8B-Modelle in Q4_K_M brauchen etwa 6 GB VRAM. Eine RTX 3060 oder RTX 4060 8GB sollte rund 60 bis 85 Token pro Sekunde liefern.
  • 13B- bis 14B-Modelle in Q4_K_M brauchen etwa 10 GB. Eine RTX 4070 oder RTX 3080 12GB sollte ungefähr 40 bis 60 Token pro Sekunde erreichen.
  • 32B- bis 35B-Modelle in Q4_K_M brauchen etwa 22 GB. Eine RTX 3090 oder RTX 4090 24GB sollte rund 25 bis 40 Token pro Sekunde schaffen.
  • 70B-Modelle in Q4_K_M brauchen etwa 48 GB, zum Beispiel zwei RTX-3090-Karten oder eine RTX 6000 Ada, bei ungefähr 15 bis 25 Token pro Sekunde.

Voraussetzungen für GPU-Passthrough

Unter Linux reicht es nicht, normale GPU-Treiber auf dem Host zu installieren, damit Container die GPU nutzen können. Das offizielle NVIDIA Container Toolkit muss installiert sein, damit CUDA-Aufrufe aus dem Container den Kernel erreichen.

Auf AMD-Hardware verwendest du den ROCm-Tag des Images (ollama/ollama:rocm) und reichst die Geräteknoten /dev/kfd und /dev/dri in den Container durch.

Docker Desktop unter Windows mit WSL2 bringt eigene Eigenheiten der virtuellen Netzwerkbrücke mit. Symptome sind unerreichbare Container oder Socket-Fehler, und sie deuten meist auf Routing-Probleme zwischen Host und Container in dieser Brücke hin.

Die Compose-Datei schreiben

Lege zuerst ein Arbeitsverzeichnis auf dem Server an:

mkdir -p ~/local-ai && cd ~/local-ai

Als Nächstes kommt die docker-compose.yml. Aktuelle Compose-Spezifikationen markieren den version-Schlüssel auf oberster Ebene als veraltet, also lass ihn weg. Zuerst kommt der Ollama-Dienst:

services:
  ollama:
    image: ollama/ollama:0.6.5
    container_name: ollama
    restart: unless-stopped
    environment:
      - OLLAMA_KEEP_ALIVE=24h
      - OLLAMA_MAX_LOADED_MODELS=1
      - OLLAMA_NUM_PARALLEL=2
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama_models:/root/.ollama
    networks:
      - ai_network
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

Open WebUI folgt in derselben Datei:

  open-webui:
    image: ghcr.io/open-webui/open-webui:v0.5.20
    container_name: open-webui
    restart: unless-stopped
    depends_on:
      - ollama
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_AUTH=true
      - WEBUI_SECRET_KEY=e8f901c23a4b5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0
    ports:
      - "3000:8080"
    volumes:
      - open_webui_data:/app/backend/data
    networks:
      - ai_networkvolumes:
  ollama_models:
    name: ollama_models
  open_webui_data:
    name: open_webui_datanetworks:
  ai_network:
    name: ai_network
    driver: bridge

Einige Einstellungen in diesen Blöcken verdienen einen genaueren Blick.

  • OLLAMA_KEEP_ALIVE=24h hält geladene Modelltensoren auch über lange Leerlaufphasen im VRAM, damit aktive Nutzer nicht auf ein Neuladen warten.
  • OLLAMA_MAX_LOADED_MODELS=1 lässt immer nur ein Modell den VRAM belegen. Das verhindert Fragmentierung und Abstürze durch Speichermangel.
  • 127.0.0.1:11434:11434 bindet Ollama an den Loopback-Adapter des Hosts. Externer Traffic sieht die API nicht, nur Open WebUI erreicht sie über das interne Docker-Netz.
  • WEBUI_SECRET_KEY ist der Seed zum Signieren der JWT-Session-Cookies. Erzeuge vor dem ersten Start einen starken Schlüssel mit openssl rand -hex 32.

Fest gepinnte Image-Tags sind hier wichtiger, als es scheint. Ein beweglicher Tag wie latest kann sich über Nacht unter dem Stack ändern, und ein Neustart an einem Dienstag zieht dann eine Runtime, die niemand getestet hat. Mit festen Versionen liefert ein Neuaufbau nächstes Jahr dasselbe Ergebnis wie heute, und ein Upgrade wird zu einer bewussten Änderung einer einzigen Zeile, die sich prüfen und zurückrollen lässt.

Starten und ein Modell laden

Starte den Stack im Hintergrund:

docker compose up -d

Prüfe Containerstatus und Port-Bindungen:

docker compose ps

Lade ein erstes Modell, indem du den Befehl im Ollama-Container ausführst:

docker compose exec ollama ollama pull llama3.2:8b

Bestätige, dass das Modell samt Quantisierung registriert ist:

docker compose exec ollama ollama list

TLS vor allem anderen

Port 3000 sollte nie ohne TLS und Host-Routing zum öffentlichen Netz zeigen. Caddy erledigt das gut, weil es HTTPS-Zertifikate automatisch verwaltet. Installiere es auf dem Host und schreibe /etc/caddy/Caddyfile:

ai.yourdomain.com {
    reverse_proxy 127.0.0.1:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
    }
}

Lade Caddy neu, damit es ein Zertifikat holt und über eine verschlüsselte Verbindung zu proxyen beginnt:

sudo systemctl reload caddy

Mehr als Chat

Irgendwann wollen Teams autonome mehrstufige Agenten und Workflow-Automatisierung, nicht nur Unterhaltungen. Open WebUI kann dann neben Orchestrierungs-Frameworks wie Dify laufen oder neben einem Backend mit hohem Durchsatz wie vLLM. Weil Ollama im internen Netz eine Standard-REST-API anbietet, können andere Workflow-Tools an derselben Brücke seine Modelle direkt nutzen.

Fehlerbehebung

Häufige Probleme mit Ursachen und Lösungen.

  • WebUI zeigt einen Verbindungsfehler zum Backend. Ursache ist eine falsche OLLAMA_BASE_URL oder ein Netzwerk-Mismatch zwischen Containern. Prüfe, ob die Variable dem internen DNS-Namen http://ollama:11434 entspricht, und teste dann die Erreichbarkeit aus dem Open-WebUI-Container heraus mit curl auf den Pfad /api/tags beim Ollama-Hostnamen.
  • Ollama erkennt die CUDA-GPU nicht. Entweder fehlt das NVIDIA Container Toolkit, oder der Compose-Datei fehlt ein GPU-Reservierungsblock. Installiere nvidia-container-toolkit auf dem Host, führe sudo systemctl restart docker aus und prüfe, ob die Reservierungen zur Compose-Spezifikation passen.
  • Token pro Sekunde fallen mit der Zeit stark ab. Das Modell ist größer als der verfügbare VRAM, also wandern Layer in den System-RAM. Sieh dir die Belegung mit nvidia-smi an und wechsle dann zu einem kleineren Modell oder einer kompakteren Quantisierung (Q4_K_M statt Q8_0).
  • Permission denied (Zugriff verweigert) auf dem Volume open_webui_data. Die Verzeichnisrechte auf dem Host passen nicht zur UID 1000 des Containerprozesses. Führe sudo chown -R 1000:1000 /var/lib/docker/volumes/open_webui_data aus.
  • WebSocket-Abbrüche beim Streaming. Der Reverse Proxy puffert Streaming-Antworten oder lässt Upgrade-Anfragen scheitern. Stelle sicher, dass er die Header Upgrade und Connection sauber weiterreicht und die Pufferung aus ist.

Backups

Benutzerkonten, Chatverlauf, RAG-Indizes und Konfiguration müssen erhalten bleiben. Modellgewichte lassen sich jederzeit neu herunterladen, also lass sie aus den Backups heraus, um Platz zu sparen. Schreibe ein sicheres, nicht destruktives Skript unter /usr/local/bin/backup-local-ai.sh. Es beginnt mit der Interpreterzeile und dem Strict Mode:

#!/usr/bin/env bash
set -euo pipefail

Der Hauptteil legt ein Backup-Verzeichnis und einen Dateinamen mit Zeitstempel fest, pausiert Open WebUI, archiviert das Daten-Volume und startet den Container neu:

BACKUP_DIR="/var/backups/local-ai"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
TARGET_FILE="${BACKUP_DIR}/open_webui_data_${TIMESTAMP}.tar.gz"mkdir -p "${BACKUP_DIR}"echo "Stopping Open WebUI container..."
docker stop open-webuiecho "Archiving Open WebUI database and user storage..."
tar -czf "${TARGET_FILE}" -C /var/lib/docker/volumes/open_webui_data/_data .echo "Restarting Open WebUI container..."
docker start open-webuiecho "Cleaning backups older than 14 days..."
find "${BACKUP_DIR}" -type f -name "*.tar.gz" -mtime +14 -deleteecho "Backup execution complete: ${TARGET_FILE}"

Mach es ausführbar und öffne die Crontab:

sudo chmod +x /usr/local/bin/backup-local-ai.sh
sudo crontab -e

Füge dann eine Zeile hinzu, damit es täglich um 3:00 Uhr läuft:

0 3 * * * /usr/local/bin/backup-local-ai.sh >> /var/log/local-ai-backup.log 2>&1

Abschließende Checkliste

  • Netzwerkisolation: Ollamas Port 11434 ist an Loopback (127.0.0.1) gebunden und öffentlich nicht erreichbar.
  • Authentifizierung: WEBUI_AUTH=true ist in Open WebUI explizit gesetzt.
  • Schlüsselintegrität: ein eigener 64-stelliger WEBUI_SECRET_KEY ist konfiguriert.
  • Image-Pinning: Images nutzen feste Versionen, keine beweglichen Tags.
  • VRAM-Limits: Keep-Alive und Parallelitätsgrenzen sind so eingestellt, dass der GPU-Treiber nicht abstürzt.
  • Backups: Datenbank-Volumes werden täglich mit Aufbewahrungsfrist archiviert.

Zur Referenz: Die maßgebliche Dokumentation findet sich im GitHub-Repository von Ollama, in der Dokumentation des NVIDIA Container Toolkit und in der Docker-Compose-Spezifikation.