# Docker-Deployment auf `100.103.83.12` Der Compose-Stack betreibt Test-Frontend und FastAPI-Agent gemeinsam. Er startet keinen zweiten Ollama-Container, sondern verbindet sich mit dem vorhandenen externen Docker-Netz `ollama_default`. ## Voraussetzungen Auf dem Zielhost müssen vorhanden sein: - Docker Engine mit Compose-Plugin; - das externe Netz `ollama_default`; - ein darin erreichbarer Ollama-Container; - die Modelle `qwen3.8:27b` und `bge-m3` in dieser Ollama-Instanz; - `wissensbasis/` und entweder ein vorhandenes `data/index.db` oder genügend Zeit für den initialen Indexaufbau. Das Netz und seine Container/Aliase prüfen: ```bash docker network inspect ollama_default ``` Der Compose-Beispielwert nimmt den DNS-Namen `ollama` und den internen Ollama-Port `11434` an. Das ist **nicht lokal verifiziert**, weil das Netz nur auf dem Zielhost existiert. Falls der Container im Netz anders heißt, muss `OLLAMA_URL` in `.env` entsprechend gesetzt werden, beispielsweise: ```text OLLAMA_URL=http://tatsaechlicher-containername:11434 ``` Die veröffentlichte Host-Portnummer `11435` ist innerhalb des gemeinsamen Docker-Netzes normalerweise nicht relevant; Container sprechen den internen Port des Ollama-Containers an. ## Konfiguration ```bash cp .env.example .env ``` Dann `.env` anpassen: 1. `PV_API_KEY` durch einen starken zufälligen Wert ersetzen; 2. optional einen getrennten `PV_ADMIN_API_KEY` setzen; 3. `OLLAMA_URL` anhand des Netzwerk-Alias prüfen; 4. `PUID`/`PGID` auf den Besitzer von `data/` setzen. Vor dem ersten Start das gitignored Bind-Mount mit diesen IDs anlegen (Beispiel für `1000:1000`): ```bash mkdir -p data sudo chown 1000:1000 data ``` Ohne diesen Schritt kann Docker ein fehlendes Verzeichnis als `root` anlegen; der absichtlich unprivilegierte Agent könnte dann weder `index.db` noch `audit.db` schreiben. `.env` ist gitignored und darf nicht committed werden. Compose verwendet die Datei nur zur Interpolation der ausdrücklich in `compose.yaml` aufgelisteten Variablen; sonstige lokale Secrets werden nicht pauschal in den Container durchgereicht. ## Start und automatischer Index-Bootstrap ```bash docker compose build docker compose up -d docker compose ps docker compose logs --follow pv-agent ``` Vor dem API-Start führt das Image automatisch `python -m agent.bootstrap` aus. Der Bootstrap prüft, ob `data/index.db` Chunks und vollständige Vektoren für das konfigurierte Embedding-Modell enthält. Fehlt der Index oder ist er unvollständig, wird er aus dem read-only eingebundenen `wissensbasis/` über Ollama neu erzeugt. Erst danach startet FastAPI. Schlägt die Einbettung fehl, beendet sich der Container bewusst mit Fehler, statt einen unvollständigen Produktionsindex zu verwenden. Der Index wird absichtlich beim **ersten Containerstart**, nicht in einem Dockerfile-`RUN` erzeugt: Nur zur Laufzeit ist das externe Netz `ollama_default` zuverlässig verfügbar, und der Index bleibt als Hostdatenstand in `./data`, statt veraltet im Image zu liegen. Beim ersten Lauf kann der Start mehrere Minuten dauern; der Healthcheck hat dafür eine Startfrist von 15 Minuten. Aufruf im Tailscale-Netz: ```text http://100.103.83.12:8080/ ``` Im Frontend denselben Wert wie `PV_API_KEY` als Service-Key eingeben. Der Prozess läuft als `PUID:PGID`. `data/` muss für diese IDs schreibbar sein, damit Bootstrap, Audit-Log und `/v1/reindex` funktionieren. Ein manueller, erzwungener Neuaufbau bleibt möglich: ```bash docker compose down rm data/index.db docker compose up -d ``` ## Smoke-Tests ```bash curl --fail http://100.103.83.12:8080/v1/health curl --fail \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{"question":"Wie hoch ist der steuerfreie Tagesgeldsatz?","mode":"knowledge"}' \ http://100.103.83.12:8080/v1/ask ``` `/v1/health` muss `"status":"ok"` liefern. Ein Status `degraded` bedeutet in der Regel, dass der Index fehlt oder Ollama unter dem konfigurierten Container-DNS-Namen nicht erreichbar ist. ## Fragen-, Antwort- und Bewertungsprotokoll Compose aktiviert standardmäßig ein detailliertes Audit: - `data/audit.db`: persistente SQLite-Datenbank mit Request-ID, Frage, Antwort, Status, Zitaten, Quellen, Konflikten, Suchplan, Modell, Laufzeit und Regenerierungen; - Tabelle `ratings`: Daumen hoch/runter plus optionales Bewertungsfeedback; - Tabelle `comments`: mehrere unabhängige Kommentare pro Antwort; - `docker compose logs --follow pv-agent`: dieselben Ereignisse als mit `AUDIT ` präfixierte JSON-Zeilen für die Betriebsdiagnose; Docker rotiert diese Logs bei 50 MB und behält fünf Dateien. Letzte Einträge strukturiert anzeigen: ```bash docker compose exec pv-agent python -m agent.cli audit --limit 20 ``` Standardaufbewahrung: 30 Tage; Bereinigung erfolgt beim Öffnen des Audit-Stores. Konfiguration: ```dotenv PV_AUDIT_ENABLED=true PV_AUDIT_LOG_CONTENT=true PV_AUDIT_STDOUT=true PV_AUDIT_RETENTION_DAYS=30 ``` Fragen und Antworten können sensible Freitexte enthalten. Zugriff auf `data/audit.db`, Backups und Docker-Logs ist deshalb auf Administratoren zu beschränken. Mit `PV_AUDIT_LOG_CONTENT=false` bleiben nur technische Metadaten und KB-IDs erhalten; Frage, Antwort, Quellenbeschreibungen, Konflikttext, Suchplan, Bewertungsfeedback und Kommentare werden dann nicht gespeichert oder nach stdout geschrieben. API-Keys und Authorization-Header werden nie protokolliert. ## Sicherheitsprofil - Port `8080` wird nur an die Tailscale-Adresse `100.103.83.12` gebunden. - `PV_API_KEY` ist für den Compose-Start verpflichtend. - Root-Dateisystem ist read-only; nur `./data` ist schreibbar. - Alle Linux-Capabilities werden entfernt; `no-new-privileges` ist aktiv. - `wissensbasis/` wird read-only eingebunden. - Frontend und API sind same-origin; es ist keine CORS-Freigabe nötig. - Außerhalb des verschlüsselten Tailnets ist TLS vor dem Dienst erforderlich. ## Aktualisierung ```bash git pull docker compose build --pull docker compose up -d docker image prune ``` Nach Änderungen an der Wissensbasis: ```bash docker compose run --rm pv-agent python -m agent.cli ingest docker compose up -d ```