Local Deployment

Outpost per Docker Compose selbst betreiben — der Weg für Self-Hosting-Profis

Diese Seite beschreibt den Docker-Weg: einen selbst betriebenen Outpost auf deiner eigenen Hardware. Danach hast du eine laufende, mit meinGPT verbundene Outpost-Instanz auf deinem Server. Stelle sicher, dass die Voraussetzungen erfüllt sind, bevor du startest.

Nur auf einem Arbeitsplatz-Rechner?

Wenn du keinen eigenen Server betreibst, ist die Desktop-App meist der einfachere Weg: geführte Kopplung, Embeddings bereits integriert, automatische Updates — ganz ohne Docker. Dieser Docker-Weg ist für Teams, die volle Kontrolle über jeden Baustein wollen.

Überblick

Der lokale Outpost besteht aus diesen Diensten, verwaltet per Docker Compose:

DienstZweck
OutpostAPI-Server — beantwortet Anfragen und liefert Datei-Downloads
Outpost-workerIngestion-Pipeline — verarbeitet und indexiert Dokumente
databasePostgreSQL mit VectorChord — speichert Ingestion-Metadaten und Vektor-Embeddings
ollamaLokaler Embedding-Server (OpenAI-kompatible API) — eine von mehreren Optionen
pikoDer gebündelte Tunnel-Sidecar — verbindet den Outpost mit meinGPT, ohne Ports öffentlich zu machen

Tunnel: Sidecar heute, Go-Bridge als Richtung

Der Docker-Weg nutzt heute den gebündelten Tunnel-Sidecar (die piko-Komponente) als Standard-Transport. Wir migrieren schrittweise auf den Go-Bridge-Agenten, den die Desktop-App bereits einsetzt. Halte dich vorerst an den hier gezeigten Sidecar.

Dein Projektverzeichnis sieht am Ende so aus:

datavault-local/
├── config/
│   ├── vault.env           # Zugangsdaten und IDs (aus den meinGPT-Einstellungen)
│   └── app_config.yaml     # Vault-Konfiguration
├── data/
│   ├── vault/              # Lokale Dokumente für die Ingestion (optional)
│   ├── postgres/           # Postgres-Daten (wird automatisch befüllt)
│   └── ollama/             # Cache des Embedding-Modells (wird automatisch befüllt)
├── documents/              # Optionaler zusätzlicher Read-only-Mount
└── docker-compose.yaml     # Dienst-Definitionen

data/vault/ brauchst du nur, wenn du lokale Dateien von der Festplatte indexieren willst. Sind alle Quellen cloud-basiert (SharePoint, Google Drive usw.), kannst du es weglassen.

Schritt 1 — Verzeichnisstruktur anlegen

mkdir datavault-local
cd datavault-local
mkdir -p config data/vault data/postgres data/ollama documents

Schritt 2 — Environment-Datei anlegen

Hole dir Outpost ID und Outpost Secret aus dem meinGPT-Dashboard (siehe Outpost anlegen → ID & Secret) und trage sie unten ein.

config/vault.env
VAULT_ID=your-vault-id
VAULT_SECRET=your-vault-secret
MEINGPT_URL=https://app.meingpt.com
 
POSTGRES_USER=datavault
POSTGRES_PASSWORD=your-postgres-password
 
OPENAI_BASE_URL=http://ollama:11434/v1
OPENAI_API_KEY=local-dev
OPENAI_EMBEDDING_MODEL=bge-m3
OPENAI_EMBEDDING_DIMENSIONS=1024

Schritt 3 — Outpost-Konfiguration anlegen

Werte wie $VAULT_ID verweisen auf die Environment-Variablen aus vault.env — sie werden zur Laufzeit automatisch aufgelöst.

config/app_config.yaml
version: 1.0
meingpt_url: $MEINGPT_URL
 
vault:
  id: $VAULT_ID
  secret: $VAULT_SECRET
  standalone_mode: false
  data_dir: ./tmp
  ingestion_interval: 300
  tasks_batch_size: 3
  chunk_size: 256
  chunk_overlap: 26
 
metadata:
  # 'deployment_type' ist nur ein Legacy-Label — der Storage nutzt immer PostgreSQL/VectorChord.
  # 'vault' und 'vault-worker' müssen auf DIESELBE Postgres zeigen, damit sie sich die Task-Queue teilen.
  deployment_type: "cloud"
  postgres:
    user: $POSTGRES_USER
    password: $POSTGRES_PASSWORD
    host: database
    port: 5432
    database: datavault
 
embedding_model:
  provider: "openai"
  model: $OPENAI_EMBEDDING_MODEL
  base_url: $OPENAI_BASE_URL
  api_key: $OPENAI_API_KEY
  embedding_dimensions: $OPENAI_EMBEDDING_DIMENSIONS
  rpm: 1000
  tpm: 100000
 
logging:
  log_level: "INFO"
  log_to_file: true
  log_file_path: "logs/app.log"
  uvicorn_log_file_path: "logs/uvicorn.log"
 
data_pools:
  - id: your-datapool-id-from-meinGPT
    type: local
    base_path: /data/vault

Hinweis

Lass standalone_mode: false und den piko-Dienst aktiv. Das ist der Tunnel-Sidecar, der deinen lokalen Outpost mit meinGPT verbindet.

Schritt 4 — Docker-Compose-Datei anlegen

Hinweis

Ersetze your-vault-id im piko-Kommando unten durch der Outpost ID aus vault.env.

docker-compose.yaml
services:
  vault:
    image: meingpt/vault:latest
    ports:
      - 8080:8080
    depends_on:
      database-init:
        condition: service_completed_successfully
      ollama:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - vault_network
    volumes:
      - ./config:/etc/vault:ro
      - ./data/vault:/data/vault
      # Optional: lokales Verzeichnis für die Ingestion einbinden
      - ./documents:/app/documents:ro
    environment:
      - VAULT_CONFIG_FILE_PATH=/etc/vault/app_config.yaml
    env_file:
      - ./config/vault.env
 
  vault-worker:
    image: meingpt/vault:worker-latest
    ports:
      - 8081:8080
    depends_on:
      database-init:
        condition: service_completed_successfully
      ollama:
        condition: service_healthy
      vault:
        condition: service_started
    restart: unless-stopped
    networks:
      - vault_network
    volumes:
      - ./config:/etc/vault:ro
      - ./data/vault:/data/vault
      # Optional: lokales Verzeichnis für die Ingestion einbinden
      - ./documents:/app/documents:ro
    environment:
      - VAULT_CONFIG_FILE_PATH=/etc/vault/app_config.yaml
    env_file:
      - ./config/vault.env
 
  database:
    image: tensorchord/vchord-suite:pg17-20260401
    command:
      - postgres
      - -c
      - shared_preload_libraries=vchord.so,vchord_bm25.so,pg_tokenizer.so
      - -c
      - search_path="$$user", public, bm25_catalog, tokenizer_catalog
    ports:
      - 5432:5432
    env_file:
      - ./config/vault.env
    environment:
      - POSTGRES_DB=datavault
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d datavault"]
      interval: 5s
      timeout: 5s
      retries: 20
    networks:
      - vault_network
 
  database-init:
    image: tensorchord/vchord-suite:pg17-20260401
    depends_on:
      database:
        condition: service_healthy
    env_file:
      - ./config/vault.env
    environment:
      - POSTGRES_DB=datavault
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        PGPASSWORD="$${POSTGRES_PASSWORD}" psql \
          -h database \
          -U "$${POSTGRES_USER}" \
          -d "$${POSTGRES_DB}" <<'SQL'
        \set ON_ERROR_STOP on
 
        CREATE EXTENSION IF NOT EXISTS vector;
        CREATE EXTENSION IF NOT EXISTS vchord CASCADE;
        CREATE EXTENSION IF NOT EXISTS pg_tokenizer CASCADE;
        CREATE EXTENSION IF NOT EXISTS vchord_bm25 CASCADE;
 
        SET search_path TO "$$user", public, bm25_catalog, tokenizer_catalog;
 
        DO $$$$
        BEGIN
          EXECUTE format(
            'ALTER DATABASE %I SET search_path TO "$$user", public, bm25_catalog, tokenizer_catalog',
            current_database()
          );
        END
        $$$$;
 
        DO $$$$
        BEGIN
          IF NOT EXISTS (
            SELECT 1
            FROM tokenizer_catalog.tokenizer
            WHERE name = 'chunks_token'
          ) THEN
            PERFORM create_tokenizer('chunks_token', $$tokenizer$$
        model = "llmlingua2"
        $$tokenizer$$);
          END IF;
        END
        $$$$;
        SQL
    restart: "no"
    networks:
      - vault_network
 
  ollama:
    image: ollama/ollama:latest
    # Beim ersten Start das Embedding-Modell vorab laden, damit vault es sofort nutzen kann.
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        ollama serve &
        SERVE_PID=$$!
        export OLLAMA_HOST=http://127.0.0.1:11434
        until ollama list >/dev/null 2>&1; do sleep 1; done
        ollama pull bge-m3
        wait $$SERVE_PID
    volumes:
      - ./data/ollama:/root/.ollama
    networks:
      - vault_network
    healthcheck:
      # Wird erst „healthy", wenn das Embedding-Modell vollständig geladen ist —
      # das gated den Start von vault/vault-worker, damit erste Embed-Calls nicht fehlschlagen.
      test: ["CMD-SHELL", "OLLAMA_HOST=http://127.0.0.1:11434 ollama list | grep -q bge-m3"]
      interval: 10s
      timeout: 5s
      retries: 60
      start_period: 30s
 
  piko:
    # Der gebündelte Tunnel-Sidecar (heute Piko; Migration auf den Go-Bridge-Agenten läuft).
    image: ghcr.io/andydunstall/piko:latest
    command:
      - agent
      - http
      # "your-vault-id" durch die Vault ID aus vault.env ersetzen
      - your-vault-id
      - vault:8080
      - --connect.url
      - https://vault-proxy.meingpt.com
    env_file:
      - ./config/vault.env
    depends_on:
      vault:
        condition: service_started
    networks:
      - vault_network
 
networks:
  vault_network:

Embedding-Modell: Wahl, kein Muss

Diese Konfiguration nutzt bge-m3 (1024 Dim, mehrsprachig — funktioniert gut für Deutsch) über den lokalen ollama-Dienst. Das ist eine bequeme Standardwahl für Docker, kein Muss: Du kannst jeden OpenAI-kompatiblen Endpunkt einsetzen — etwa nomic-embed-text (768 Dim), mxbai-embed-large (1024 Dim) oder einen Cloud-Anbieter. Passe dazu OPENAI_BASE_URL, OPENAI_EMBEDDING_MODEL und OPENAI_EMBEDDING_DIMENSIONS in vault.env an. Alle Optionen: Embedding Models.

Anders bei der Desktop-App: Dort ist ein offline nutzbares, für Deutsch optimiertes Embedding-Modell bereits integriert — kein Ollama, keine GPU, keine Einrichtung.

GPU: Ollama läuft in Docker standardmäßig nur auf der CPU. Mit einer NVIDIA-GPU auf dem Host ergänze deploy: { resources: { reservations: { devices: [{ driver: nvidia, count: all, capabilities: [gpu] }] } } } im ollama-Dienst für deutlich mehr Durchsatz.

Schritt 5 — Deployen

  1. Wenn du lokale Dateien indexieren willst, lege sie in data/vault/ ab
  2. Images holen: docker compose pull
  3. Dienste starten: docker compose up -d
  4. Health prüfen: curl http://localhost:8080/health/
  5. Logs beobachten: docker compose logs -f database ollama vault vault-worker

Beim ersten Start lädt ollama das Modell bge-m3. vault und vault-worker warten, bis es verfügbar ist.

Troubleshooting

  • Dienst-Status prüfen: docker compose ps
  • API-Logs ansehen: docker compose logs vault
  • Ingestion-Logs ansehen: docker compose logs vault-worker
  • Postgres testen: docker compose exec database pg_isready -U datavault -d datavault
  • Ollama testen: docker compose exec ollama sh -c "OLLAMA_HOST=http://127.0.0.1:11434 ollama list"
  • Dienste neu starten: docker compose restart

Häufiger Stolperstein: Ingestion läuft nicht

Wenn die Ingestion nie startet (keine Fehler, aber Dokumente bleiben un-indexiert), prüfe, ob der metadata.postgres-Block in app_config.yaml vorhanden ist und beidevault und vault-worker — denselben database-Host auflösen. Sie müssen sich eine Postgres teilen, damit der Worker die Tasks sieht, die die API einreiht.

Häufiger Stolperstein: Datenbank falsch initialisiert

Wenn du einmal mit falschem Datenbank-Image oder falschem Volume-Pfad gestartet hast, entferne das kaputte Datenverzeichnis und starte neu:

docker compose down
rm -rf data/postgres
mkdir -p data/postgres
docker compose up -d
War diese Seite hilfreich?