Self-Hosting-Konfiguration
Vollständige Referenz für Docker-Umgebungsvariablen, Convex-Backend-Variablen, Service-Topologie und Persistenz von Volumes.
Diese Seite ist die vollständige Konfigurationsreferenz für eine selbst gehostete Owlat-Instanz. Eine Schritt-für-Schritt-Einrichtung finden Sie unter Self-Hosting.
Zwei Konfigurationsebenen
Owlat nutzt zwei getrennte Konfigurationsebenen. Sie zu verwechseln ist der häufigste Fehler bei der Einrichtung.
- Docker-
.env— wird von Docker Compose beim Start der Container gelesen. Steuert Ports, zwischen Containern geteilte Secrets und die vom Browser aufgerufenen URLs. - Convex-Umgebungsvariablen — werden von den Serverless-Functions innerhalb des Convex-Backends gelesen. Werden nach dem Deployment über
npx convex env setgesetzt. Steuern das Anwendungsverhalten: E-Mail-Provider, Auth-Secrets, Absenderidentität, Integrationen.
Docker-Umgebungsvariablen
Diese gehören in die Datei .env im Projektstammverzeichnis. Docker Compose liest sie beim Starten der Container.
Convex-Backend
| Variable | Erforderlich | Standard | Beschreibung |
|---|---|---|---|
INSTANCE_SECRET | Ja | — | Instanzidentität des Convex-Backends. Mit openssl rand -hex 32 erzeugen. |
CONVEX_ADMIN_KEY | Ja | — | Admin-Key zum Deployen der Functions. Wird nach dem ersten Start über docker compose exec convex ./generate_admin_key.sh erzeugt. |
Öffentliche URLs
Diese müssen aus dem Browser des Nutzers erreichbar sein — verwenden Sie keine Docker-internen Hostnamen.
| Variable | Erforderlich | Standard | Beschreibung |
|---|---|---|---|
NUXT_PUBLIC_CONVEX_URL | Ja | http://localhost:3210 | URL des Convex-Backends (Browser → Convex). |
NUXT_PUBLIC_CONVEX_SITE_URL | Ja | http://localhost:3211 | URL des Convex-Site-Proxys (Browser → HTTP-Actions). |
NUXT_PUBLIC_SITE_URL | Ja | http://localhost:3000 | URL der Webanwendung. |
MTA-Konfiguration
Der eingebaute MTA läuft nur, wenn er der Zustell-Provider ist (EMAIL_PROVIDER=mta) oder wenn postbox/inbox ihn für eingehende Mail benötigen — gesteuert über das Docker-Compose-Profil mta. Der Standard-Self-Host liefert COMPOSE_PROFILES=mta aus; ein Deployment mit Resend/SES, ein reines Empfangs- oder ein reines IMAP-Deployment lässt mta weg und betreibt ihn nicht. Diese Variablen gelten nur, wenn der MTA aktiv ist. Siehe Betriebsmodi.
| Variable | Erforderlich | Standard | Beschreibung |
|---|---|---|---|
MTA_API_KEY | Ja | — | Gemeinsames Secret für die Authentifizierung Convex → MTA. Mit openssl rand -base64 32 erzeugen. |
MTA_WEBHOOK_SECRET | Ja | — | HMAC-Secret für Webhook-Callbacks MTA → Convex. Mit openssl rand -base64 32 erzeugen. |
EHLO_HOSTNAME | Für Zustellung | mail.localhost | Hostname für SMTP EHLO/HELO. Der Platzhalter lässt den Service starten, dessen IP bleibt jedoch in Quarantäne, bis der Hostname zu einem Forward-Confirmed PTR passt. |
EHLO_HOSTNAMES | Nein | — | JSON-Zuordnung von Versand-IP zu EHLO-Hostname für Deployments mit mehreren IPs. |
MTA_GENERIC_PTR_SUFFIXES | Nein | — | Zusätzliche, kommagetrennte Provider-Standard-PTR-Suffixe, die als reputationsschwach markiert werden sollen. |
MTA_ALLOW_UNVERIFIED_FCRDNS | Nein | false | Nur für Laborumgebungen: Umgehung der FCrDNS-Quarantäne. Niemals für die Zustellung ins Internet aktivieren. |
MTA_IPV6_ENABLED | Nein | false | Ausdrückliche Freigabe für ausgehendes IPv6. Solange false, werden IPv6-Pool-Einträge abgelehnt; bei true bleiben sie an IPv4-Identität, PTR/AAAA und die SPF-Bereitschaft des Return-Path gebunden. |
RETURN_PATH_DOMAIN | Für Zustellung | bounces.localhost | Domain für VERP-Return-Path-Adressen bei Bounces. Der Standard bounces.localhost startet problemlos; für den produktiven Versand erforderlich, dort mit einem MX-Record auf Ihren Server. |
IP_POOLS_TRANSACTIONAL | Nein | 127.0.0.1 | Kommagetrennte IPs für die Zustellung transaktionaler E-Mails. |
IP_POOLS_CAMPAIGN | Nein | 127.0.0.1 | Kommagetrennte IPs für die Zustellung von Kampagnen-/Marketing-E-Mails. |
DKIM_KEYS | Nein | {} | DKIM-Signaturschlüssel als JSON. Siehe DNS- & E-Mail-Setup. |
WORKER_CONCURRENCY | Nein | 50 | Anzahl paralleler MTA-Worker-Threads. |
MTA_LOG_LEVEL | Nein | info | Log-Ausführlichkeit des MTA: debug, info, warn, error. |
Port-Überschreibungen
Alle Ports lassen sich ändern, falls die Standardwerte mit vorhandenen Services kollidieren.
| Variable | Standard | Service |
|---|---|---|
CONVEX_PORT | 3210 | Convex-Backend-API |
CONVEX_SITE_PORT | 3211 | Convex-HTTP-Actions |
DASHBOARD_PORT | 6791 | Convex-Dashboard (erfordert --profile dashboard; nur an 127.0.0.1 gebunden — Zugriff über SSH-Tunnel) |
WEB_PORT | 3000 | Webanwendung |
MTA_HTTP_PORT | 3100 | MTA-HTTP-API |
MTA_SMTP_PORT | 25 | MTA-SMTP (Bounce-Verarbeitung) |
Die Ports von Convex, MTA-HTTP und Dashboard binden standardmäßig nur an localhost (127.0.0.1). CONVEX_BIND (Standard 127.0.0.1) legt fest, an welches Interface das Convex-Backend bindet, und REDIS_PASSWORD setzt das Redis-Authentifizierungspasswort.
Redis und ClamAV veröffentlichen keinen Host-Port — sie sind ausschließlich über das interne Docker-Netzwerk erreichbar (redis:6379, clamav:3310); es gibt daher keinen Schalter REDIS_PORT/CLAMAV_PORT zur Host-Überschreibung. (CLAMAV_PORT wird am MTA-Container als die interne Adresse gesetzt, die dessen Scan-Client anspricht; ein Host-Port wird damit nicht gemappt.)
Analytics (optional)
| Variable | Standard | Beschreibung |
|---|---|---|
NUXT_PUBLIC_POSTHOG_API_KEY | — | PostHog-Projekt-API-Key für clientseitiges Tracking. |
NUXT_PUBLIC_POSTHOG_HOST | https://eu.i.posthog.com | URL der PostHog-Instanz. |
Deployment-Modus
Diese Variablen steuern, welche Oberfläche die Web-App anzeigt und ob In-App-Updates ausgeführt werden können. Die Standardwerte passen zu einer selbst gehosteten Installation — Sie müssen sie selten ändern.
| Variable | Standard | Beschreibung |
|---|---|---|
OWLAT_DEPLOYMENT_MODE | selfhost | Wird von der Web-App gelesen (config.public.deploymentMode). Steuert das Onboarding-Banner für Self-Hosting. Für ein OSS-Deployment auf selfhost belassen. |
OWLAT_INSTALL_DIR | ./ | Absoluter Pfad zu diesem Repository auf dem Host. Der updater-Sidecar bindet ihn ein, um Compose-Templates zu schreiben und docker compose pull && up -d auszuführen. Für In-App-Updates erforderlich. |
Das owlat-Setup-CLI schreibt einen Wert für OWLAT_HOSTED_MODE in die .env, kein Service in diesem OSS-Repository liest ihn jedoch — die Control Plane der gehosteten Cloud (und deren Abrechnung) wurde in ein separates, privates Repository ausgelagert. Ihn zu setzen hat auf eine selbst gehostete Instanz keine Auswirkung.
Image-Pinning (optional)
Die Compose-Datei pinnt Upstream-Images über eigene *_VERSION-Variablen auf Minor-Versionen, jeweils mit einem fest hinterlegten Standardwert. Überschreiben Sie sie nur, um eine andere Version zu pinnen; die Compose-Dateien produktiver Releases fixieren diese zusätzlich auf @sha256-Digests.
| Variable | Standard | Image |
|---|---|---|
CONVEX_BACKEND_VERSION | latest | ghcr.io/get-convex/convex-backend |
CONVEX_DASHBOARD_VERSION | latest | ghcr.io/get-convex/convex-dashboard |
REDIS_VERSION | 7.4-alpine | redis |
CLAMAV_VERSION | stable | clamav/clamav |
CADDY_VERSION | 2.8-alpine | caddy (nur mit --profile tls verwendet) |
Die eigenen Images von Owlat (web, mta, updater, convex-deploy, code-worker) werden mit OWLAT_VERSION getaggt — der Tag für den Image-Pull ist standardmäßig latest, während das Build-Argument im Container standardmäßig auf dem Sentinel dev für lokale Builds steht. Die Release-Pipeline schreibt den gepinnten Tag; bearbeiten Sie OWLAT_VERSION, OWLAT_GIT_SHA oder OWLAT_BUILD_DATE daher nicht von Hand.
Convex-Umgebungsvariablen
Diese werden nach dem Deployen der Functions gesetzt. Sie steuern das Verhalten auf Anwendungsebene innerhalb des Convex-Backends.
npx convex env set VAR_NAME "value" \
--url http://localhost:3210 \
--admin-key <your-admin-key>
Diese für den Normalbetrieb setzen
Setzen Sie alle diese Variablen in jedem echten Deployment. Im Code werden die meisten mit sinnvollen Fallbacks gelesen und lassen eine Function nicht abstürzen, wenn sie fehlen — Auth-Weiterleitungen, Abmeldelinks und CORS sind ohne sie jedoch falsch.
| Variable | Beschreibung |
|---|---|
SITE_URL | Öffentliche Site-URL für Auth-Weiterleitungen (z. B. http://localhost:3000). Fällt auf http://localhost:3000 zurück. |
BETTER_AUTH_SECRET | Secret zum Signieren von Auth-Sessions. Mit openssl rand -base64 32 erzeugen. |
UNSUBSCRIBE_SECRET | HMAC-Secret für signierte Abmelde-Tokens. Mit openssl rand -base64 32 erzeugen. |
EMAIL_PROVIDER | E-Mail-Provider: mta, ses, resend, smtp, mandrill oder emailit. Kein impliziter Standardwert — bleibt die Variable ungesetzt, werden Sendungen abgelehnt statt an den eingebauten MTA geleitet. |
CONVEX_SITE_URL (verwendet für Tracking-Pixel und Abmeldelinks) ist ein Convex-Built-in — convex env set lehnt es mit EnvVarNameForbidden ab. Das Backend leitet den Wert von CONVEX_SITE_ORIGIN am convex-Container ab, das docker-compose aus NUXT_PUBLIC_CONVEX_SITE_URL in Ihrer .env interpoliert. Setzen Sie die öffentliche URL dort, nicht als Umgebungsvariable einer Convex-Function.
MTA_API_URL und MTA_API_KEY sind die einzigen Variablen, die einen harten Fehler auslösen — und das nur, wenn tatsächlich eine E-Mail über den MTA-Provider versendet wird (Auth-Einladungen, Kampagnen, transaktionale Mail). Der Versand scheitert mit No system email transport configured, wenn eine der beiden nicht gesetzt ist (apps/api/convex/systemMail.ts; der MTA-Provider selbst liegt in apps/api/convex/lib/sendProviders/mta/index.ts). Setzen Sie beide immer dann, wenn EMAIL_PROVIDER=mta gilt.
| Variable | Beschreibung |
|---|---|
MTA_API_URL | URL des MTA-Service. Verwenden Sie http://mta:3100 für das Docker-Networking. |
MTA_API_KEY | Muss mit MTA_API_KEY in der Docker-.env übereinstimmen. |
MTA_WEBHOOK_SECRET | Muss mit MTA_WEBHOOK_SECRET in der Docker-.env übereinstimmen. |
Absenderidentität
| Variable | Standard | Beschreibung |
|---|---|---|
DEFAULT_FROM_EMAIL | noreply@example.com | Standard-Absenderadresse. |
DEFAULT_FROM_NAME | Owlat | Standardmäßig angezeigter Absendername. |
DEFAULT_FROM_DOMAIN | mail.owlat.app | Domain für System-E-Mails (Einladungen usw.). |
ALLOWED_ORIGINS | — | Kommagetrennte CORS-Origins (z. B. http://localhost:3000,http://localhost:3001). |
LLM-Provider (optional)
Owlat spricht mit einem einzigen austauschbaren LLM-Provider (ADR-007). Dieselbe Konfiguration versorgt KI-Agentenantworten, Übersetzungen, Embeddings für den Knowledge Graph und den Visualisierungs-Agenten. Alles, was das Format der OpenAI Chat Completions / Embeddings spricht, funktioniert (OpenAI, OpenRouter, Ollama, lokales vLLM/LM Studio). Setzen Sie diese Variablen nur, wenn Sie ein KI-Feature-Flag aktivieren.
| Variable | Standard | Beschreibung |
|---|---|---|
LLM_PROVIDER | openai | openai, openrouter oder ollama. Wählt den Client und eine Standard-Basis-URL. |
LLM_API_KEY | — | API-Key des Providers. Für ollama nicht erforderlich. |
LLM_BASE_URL | Provider-Standard | Überschreibt den Endpunkt (für selbst gehostete/lokale Server). OpenRouter und Ollama erhalten automatisch sinnvolle Standardwerte. |
LLM_MODEL_FAST | gpt-4o-mini | Modell für schnelle Aufgaben (Klassifizieren/Extrahieren/Absichern/Zusammenfassen). |
LLM_MODEL_CAPABLE | gpt-4o | Modell für anspruchsvolle Aufgaben (Entwurf). |
LLM_EMBEDDING_MODEL | text-embedding-3-small | Embedding-Modell für den Knowledge Graph. |
OPENAI_API_KEY und OPENROUTER_API_KEY werden als Fallback-Aliase für LLM_API_KEY akzeptiert (Reihenfolge: LLM_API_KEY → OPENROUTER_API_KEY → OPENAI_API_KEY). Bevorzugen Sie bei neuen Installationen LLM_API_KEY (apps/api/convex/lib/llmProvider.ts).
LLM_PROVIDER akzeptiert nur openai, openrouter und ollama. Um Claude-Modelle zu betreiben, nutzen Sie den OpenAI-kompatiblen Weg: Setzen Sie LLM_PROVIDER=openai (oder belassen Sie den Standard), richten Sie LLM_BASE_URL auf einen OpenAI-kompatiblen Endpunkt und setzen Sie LLM_MODEL_CAPABLE / LLM_MODEL_FAST auf die Claude-Modell-IDs.
Weitere Integrationen (optional)
| Variable | Beschreibung |
|---|---|
GOOGLE_SAFE_BROWSING_API_KEY | Key für die Google-Safe-Browsing-API v4 zur Prüfung der URL-Reputation. |
MTA_INTERNAL_URL | Bevorzugte clusterinterne MTA-Basis-URL für alle HTTP-Aufrufe Convex→MTA (ausgehender Versand, Cache-Push, Zustell-Hooks, Anhangsprüfung); überschreibt das öffentliche MTA_API_URL. Z. B. http://mta:3100. |
MAIL_SYNC_API_URL | URL des Mail-Sync-Workers für externe IMAP-/SMTP-Konten. Ohne sie wird ein ausgehender externer Versand für jeden Empfänger als fehlgeschlagen markiert (errorCode EXTERNAL_NOT_CONFIGURED), statt zugestellt zu werden. |
MAIL_SYNC_API_KEY | Gemeinsames Secret für den Mail-Sync-Worker. |
POSTHOG_API_KEY | PostHog-API-Key für serverseitige Analytics. |
POSTHOG_HOST | URL der PostHog-Instanz (Standard: https://eu.i.posthog.com). |
Die vollständige Variablenreferenz einschließlich AWS SES, Resend und Webhooks für eingehende Kanäle finden Sie unter Umgebungsvariablen.
Service-Topologie
| Service | Ports | Hängt ab von | Healthcheck |
|---|---|---|---|
| convex | 3210 (API), 3211 (Site-Proxy) | — | curl -f http://localhost:3210/version alle 15 s |
| convex-dashboard | 6791 (nur 127.0.0.1) | convex (healthy) | — (Profil dashboard; Zugriff über SSH-Tunnel ssh -L 6791:127.0.0.1:6791 host) |
| web | 3000 | convex (healthy) | — |
| mta | 3100 (HTTP), 25 (SMTP) | redis (healthy), convex (healthy), clamav (gestartet, optional) | — |
| redis | 6379 | — | redis-cli ping alle 10 s |
| clamav | 3310 | — | clamdcheck alle 60 s (600 s Startverzögerung) (Profil clamav; aus, sofern die Dateiprüfung nicht aktiviert ist) |
| updater | 3200 (nur intern) | docker-socket-proxy | — |
| convex-deploy | — | convex (healthy) | Einmalig (Profil deploy) |
| caddy | 80, 443 | web, convex, mta | — (Profil tls) |
| code-worker | — (nur intern) | convex (healthy) | — (Profil inbox-codetasks; außerdem dev) |
| imap | 993 | convex (healthy), imap-cert-init (abgeschlossen) | — (Profil personal-mail) |
| mail-sync | — (nur intern) | convex (healthy) | — (Profil external-mail) |
| ollama | — (nur intern) | — | — (Profile ai / dev) |
Der updater-Sidecar hat keinen öffentlichen Port — die Web-App erreicht ihn über das Docker-Netzwerk unter http://updater:3200. Er bindet ausschließlich OWLAT_INSTALL_DIR mit Schreibrechten ein, um ein neues Compose-Template schreiben zu können, und erreicht die Docker-API über den Least-Privilege-Sidecar docker-socket-proxy (der den Socket schreibgeschützt einbindet) via DOCKER_HOST=tcp://docker-socket-proxy:2375 — den Docker-Socket bindet er nicht mehr direkt ein.
Der optionale Service caddy (--profile tls) ist ein Reverse Proxy, der TLS über Let's Encrypt terminiert und web, convex und mta auf Subdomains vorschaltet. Passen Sie die Caddyfile vor dem Start an Ihre Domains an, oder stellen Sie dem Stack stattdessen Ihren eigenen Reverse Proxy voran.
Der Sidecar code-worker (--profile inbox-codetasks, ebenfalls über --profile dev verfügbar) ist der KI-Coding-Agent, der Code-Tasks übernimmt. Er liest die Variablen LLM_* und GITHUB_* und ist standardmäßig aus.
Volumes
| Volume | Persistiert | Backup-Priorität |
|---|---|---|
convex-data | Datenbank, Dateispeicher, Vektorindizes | Kritisch — sämtliche Anwendungsdaten |
redis-data | MTA-Job-Queue (AOF) | Mittel — laufende E-Mail-Jobs |
clamav-data | Virensignaturen | Niedrig — werden automatisch neu heruntergeladen |
caddy-data / caddy-config | TLS-Zertifikate und Caddy-Zustand (nur mit --profile tls) | Niedrig — Zertifikate werden automatisch neu ausgestellt |
code-workspace | Checkout des Code-Workers (nur mit --profile inbox-codetasks oder --profile dev) | Niedrig — kurzlebiger Arbeitsbaum |
mail-certs | TLS-Zertifikate des IMAP-Servers (nur mit --profile personal-mail) | Niedrig — Zertifikate werden automatisch neu ausgestellt |
ollama-data | Ollama-Modelldateien (nur mit --profile ai / --profile dev) | Niedrig — Modelle werden automatisch neu heruntergeladen |