Zum Inhalt

Self-Hosting-Übersicht

Diese Seite ist die Referenz für Operations-Aufgaben rund um Vesana. Wenn du Vesana für andere hostest oder bei einem Kunden eine Instanz pflegst: hier sind die Hebel.

Verzeichnisstruktur

Auf dem Host selbst liegen in /opt/vesana/ nur Konfigurationsdateien:

/opt/vesana/
├── docker-compose.prod.yml      # Compose-Stack-Definition (gehört Vesana, wird bei Updates ersetzt)
├── docker-compose.override.yml  # optional: deine eigenen Ergänzungen (bleibt bei Updates erhalten)
├── .env                         # Secrets + Konfiguration (Klartext-Umgebungsvariablen, nur für root lesbar)
├── .env.example                 # Vorlage mit allen Variablen
└── secrets/                     # Kopie der generierten Geheimnisse (nur root; wirksam ist allein die .env)

Dazu kommen kleine Hilfsdateien des Installers (z. B. .vesana-ac-autoinstall.sh für die Active-Checker-Einrichtung) und ggf. admin-nginx/, das der Split-Container-Assistent beschreibt.

Eigene Netze, Labels, Ressourcen-Grenzen oder Bind-Mounts gehören nie in docker-compose.prod.yml, sondern in docker-compose.override.yml — siehe Eigene Anpassungen am Stack.

Alles andere — SSL-Zertifikate, Backups, Agent-/Collector-Binaries, Uploads, Icon-Assets, Avatare — liegt in benannten Docker-Volumes, nicht als Verzeichnis unter /opt/vesana. Das hat den Vorteil, dass ein docker compose down (ohne -v) niemals versehentlich Daten aus einem Host-Verzeichnis mitreißt.

Willst du in ein Volume hineinschauen oder etwas herauskopieren, geht das über einen Wegwerf-Container:

# Beispiel: Inhalt eines Volumes auflisten
docker run --rm -v vesana_backup-data:/data alpine ls -la /data

# Beispiel: Datei aus einem Volume herauskopieren
docker run --rm -v vesana_backup-data:/src -v $(pwd):/dst alpine \
  sh -c 'cp /src/irgendeine-datei /dst/'

(Volume-Namen tragen üblicherweise den Compose-Projekt-Präfix, z. B. vesana_backup-data — mit docker volume ls prüfen, falls der Präfix bei dir abweicht.)

Optionale Compose-Profile

Optionale Profile schalten zusätzliche Services an:

Profil Service Wann
Default (kein Profil) postgres, redis, init, init-binaries, api, receiver, worker, worker-scheduler, nginx, updater Immer
ai ollama AI-Features mit lokalem Ollama
agent-gateway agent-gateway Separater Port nur für Agent-/Collector-Endpunkte (Weboberfläche kann dann per Firewall abgeschottet werden) — siehe Distribution & Erreichbarkeit
admin-split, admin-split-port api-admin, nginx-admin Eigener Admin-Container — setzt der Split-Container-Assistent, nie von Hand

Backups sind kein Profil mehr — das eingebaute DR-Backup-System (siehe Backup & Disaster-Recovery) läuft immer mit, ohne separaten Sidecar.

Aktivieren:

docker compose -f docker-compose.prod.yml --profile ai up -d

Oder dauerhaft über die .env:

COMPOSE_PROFILES=ai,agent-gateway

Wichtige Umgebungsvariablen

Die .env wird vom Setup-Script generiert. Wichtige Variablen:

Pflicht

Variable Bedeutung
BASE_URL Öffentliche URL inkl. https://
POSTGRES_PASSWORD Generiert
REDIS_PASSWORD Generiert
SECRET_KEY Signaturschlüssel für Login-Tokens, generiert
FIELD_ENCRYPTION_KEY AES-256-GCM-Key für Feldverschlüsselung, generiert
UPDATER_SHARED_SECRET Geheimer Header zwischen API und Updater, generiert. Leer = ältere Installationen ohne diesen Schutz; nachrüsten durch Setzen eines zufälligen Werts (z. B. openssl rand -hex 32) und Neustart des Stacks
VESANA_SETUP_TOKEN Einmal-Code für den Setup-Wizard, generiert; nach dem Abschluss bedeutungslos

Optional / Tuning

Variable Default Bedeutung
WORKER_REPLICAS 1 Anzahl Consumer-Worker-Container
WORKER_CONCURRENCY 4 Parallelität pro Worker
WORKER_BATCH_SIZE 100 Batch-Größe pro DB-Insert-Durchlauf
DB_POOL_SIZE 10 Größe des DB-Connection-Pools
DB_MAX_OVERFLOW 20 Zusätzliche Connections über den Pool hinaus, bei Bedarf
PG_SHARED_BUFFERS nach RAM, siehe unten Postgres-Puffer
PG_WORK_MEM 16MB Sort-/Hash-Buffer pro Operation
PG_EFFECTIVE_CACHE nach RAM, siehe unten Postgres-Planner-Annahme (belegt keinen Speicher)
PG_MAX_CONNECTIONS 200 Connection-Limit
PG_SHM_SIZE nach RAM, siehe unten Obergrenze für /dev/shm des Postgres-Containers (parallele Abfragen)
PG_MAINTENANCE_WORK_MEM nach RAM, siehe unten Speicher-Deckel für Vacuum/Index-Wartung — ohne diesen Wert leitet die automatische Postgres-Tuning-Logik den Wert aus dem gesamten Host-RAM ab, was auf kleinen Maschinen zu OOM führen kann
REDIS_MAXMEMORY 512mb Redis-Speicherlimit (noeviction-Policy — Redis lehnt neue Daten ab statt alte zu verwerfen)
HTTP_PORT / HTTPS_PORT 80 / 443 Wenn andere Dienste die Ports belegen
AGENT_GATEWAY_PORT 8443 Nur relevant mit aktivem agent-gateway-Profil
AI_ENABLED false Vorgabe für die KI-Funktionen, solange unter Admin → System → KI nichts gespeichert ist
LICENSE_KEY leer Lizenzschlüssel (wirkt ohne erneute Eingabe in der Oberfläche)
VESANA_VERSION latest Image-Tag; der Updater schreibt hier die installierte Version hinein
COMPOSE_PROJECT_DIR /opt/vesana Installationsverzeichnis, das der Updater aktualisiert (setzt der Installer bei VESANA_DIR)
VESANA_PULSE on off schaltet den täglichen Instanz-Puls ab
VESANA_NGINX_KEEPALIVE leer (an) off = nginx baut je Anfrage eine neue Verbindung zu API und Receiver auf (Notschalter)

Postgres-Speicher nach Arbeitsspeicher

Bei einer Neuinstallation leitet setup.sh die Postgres-Werte der Tabelle aus dem Arbeitsspeicher des Servers ab und schreibt sie in die .env. Die Werte sind bewusst zurückhaltend, weil sich Postgres den Server mit API, Worker, Receiver, Redis und gegebenenfalls Ollama teilt:

Arbeitsspeicher PG_SHARED_BUFFERS PG_EFFECTIVE_CACHE PG_MAINTENANCE_WORK_MEM PG_SHM_SIZE
bis 2 GB 256MB 512MB 256MB 512m
4 GB 512MB 2GB 256MB 512m
8 GB 1GB 4GB 256MB 512m
16 GB 2GB 8GB 512MB 512m
32 GB 4GB 16GB 512MB 1g
64 GB und mehr 8GB 32GB 1GB 1g

Die Grenzen liegen zwischen den üblichen Größen (unter 3, 6, 12, 24 und 48 GB), weil ein Server etwas weniger meldet als seinen Nennwert. PG_WORK_MEM und PG_MAX_CONNECTIONS bleiben unabhängig vom Arbeitsspeicher bei 16MB bzw. 200 — beide vervielfachen sich je Abfrage bzw. Verbindung.

PG_SHM_SIZE ist die Obergrenze für /dev/shm im Postgres-Container (keine Reservierung). Dort legen parallele Abfragen ihren gemeinsamen Speicher an; Dockers Standard von 64 MB reicht schon für einen parallelen Hash-Join über einige Millionen Zeilen nicht — die Abfrage bricht dann mit could not resize shared memory segment … No space left on device ab. Der Wert wirkt mit der Compose-Datei ab Oktober 2026 (shm_size am Dienst postgres); ohne Eintrag in der .env gilt dort 512m.

  • Bestehende Installationen ändern sich nicht. Der Installer fasst eine vorhandene .env nie an; ein Update ändert die Werte ebenfalls nicht.
  • Die Größen-Auswahl im Einrichtungs-Assistenten senkt die Werte nicht, sie kann sie nur anheben. Unter Ressourcen → Leistung wendet ein Profil seine Werte dagegen genau so an, wie es sie anzeigt.
  • Ohne Ableitung installieren: VESANA_PG_SIZING=default beim Aufruf von setup.sh setzen — dann gelten die Werte der .env.example (256MB / 512MB / 256MB / 512m).
  • Wann von Hand zurückstellen: wenn der Server weitere speicherhungrige Dienste trägt (z. B. ein großes Ollama-Modell) und der Arbeitsspeicher knapp wird. Die Zeilen in der .env anpassen und docker compose up -d ausführen — Postgres startet dabei kurz neu.

Die vier Sizing-Profile (Klein/Mittel/Groß/XL) unter Ressourcen → Leistung setzen WORKER_REPLICAS, WORKER_CONCURRENCY, PG_SHARED_BUFFERS, PG_EFFECTIVE_CACHE, PG_WORK_MEM, PG_MAINTENANCE_WORK_MEM, PG_MAX_CONNECTIONS, DB_POOL_SIZE/DB_MAX_OVERFLOW und REDIS_MAXMEMORY in einem Rutsch — für die meisten Setups einfacher als einzelne Variablen von Hand zu justieren.

Vollständige Liste der verfügbaren Variablen in der mitgelieferten .env.example. Nach Änderungen: docker compose up -d zum Übernehmen.

SSL / TLS

Standard: automatisches selbstsigniertes Zertifikat

Beim ersten Start generiert Vesana automatisch ein selbstsigniertes Zertifikat — dadurch läuft der Setup-Wizard immer über HTTPS, auch ganz ohne eigene Domain oder eigenes Zertifikat. Dein Browser zeigt dafür eine Zertifikatswarnung, bis du ein echtes Zertifikat einspielst.

Zertifikat direkt aus Vesana (empfohlen)

Admin → System → Zertifikat stellt ein öffentliches Zertifikat selbst aus und erneuert es: Let's Encrypt oder eine eigene ACME-CA, geprüft über einen DNS-Anbieter (über 200 Anbieter, z. B. OVH, Cloudflare, IONOS, Hetzner, RFC2136 für Windows-DNS) oder über Port 80. Ein eigenes, gekauftes Zertifikat lädt man auf derselben Seite hoch. Kein certbot, kein Cron-Job, keine Änderung an der Compose-Datei — Details: TLS / Zertifikat.

Eigenes Zertifikat von Hand einspielen

Wer certbot auf dem Host behalten will: Zertifikat und Key liegen im Container unter /etc/nginx/ssl/fullchain.pem und /etc/nginx/ssl/privkey.pem — das ist ein benanntes Docker-Volume, kein Host-Verzeichnis. Eigenes Zertifikat reinkopieren:

docker run --rm \
  -v vesana_ssl:/etc/nginx/ssl \
  -v /pfad/zu/deinem/cert:/src:ro \
  alpine sh -c 'cp /src/fullchain.pem /src/privkey.pem /etc/nginx/ssl/'

docker compose -f /opt/vesana/docker-compose.prod.yml restart nginx

Solange gültige Dateien unter diesen beiden Namen im Volume liegen, überschreibt Vesana sie beim Neustart nicht mit einem neuen selbstsignierten Zertifikat — Erneuerung musst du dann selbst per Cron-Job wiederholen. Vesana erkennt so ein Zertifikat, überschreibt es nie still und warnt über den Check „TLS Certificate", bevor es abläuft.

Hinter eigenem Reverse-Proxy

Wenn der Server bereits hinter einem eigenen nginx / Traefik / HAProxy / Nginx Proxy Manager steht, terminiere TLS dort und proxiere intern auf den Vesana-Webserver-Container. Details zu Reverse-Proxy-Besonderheiten (SSE-Buffering, WebSocket-Upgrade): Distribution & Erreichbarkeit. Wie du den Webserver in das Docker-Netz deines Proxys hängst (auch über mehrere Hosts per Overlay-Netz), ohne dass ein Update es rückgängig macht, und was dabei für echte Client-Adressen und das Agent-Gateway gilt: Eigene Anpassungen am Stack.

Updates & Backups

  • Updates — GUI-Updater, Online + Offline + Notfall-CLI, kein Auto-Rollback
  • Backup & Restore — eingebautes DR-System, mehrere Zeitpläne, Disaster-Drill

Anschluss