SentryMail wird als Docker-Compose-Stack betrieben. Alle umgebungsspezifischen Werte kommen aus einer .env — es sind keine Werte im Code fest verdrahtet.
Docker Engine (aktuelle Version, ≥ 24) und Docker Compose v2 — das ist das aktuelle, in Docker integrierte docker compose-Plugin (Aufruf mit Leerzeichen). Compose v2 ist die aktuelle Generation (Versionsstände 2.x); das alte, separate docker-compose (v1, Python) ist eingestellt und wird nicht unterstützt. Prüfen mit docker compose version.
Eine Domain oder ein vorgelagerter Reverse Proxy (optional, aber empfohlen für TLS)
Ein SMTP-Postfach für den Mailversand (beliebiger Anbieter)
Der gesamte Stack (PostgreSQL, Redis, FastAPI-Backend, Frontend, Caddy) läuft auf einem Docker-Host. Die Werte sind Richtwerte; der Bedarf steigt mit Empfängerzahl, paralleler Nutzung und optionalen Business-Features (PDF-Reports, KI-Anbindung).
Ressource
Minimum
Empfohlen
CPU
2 vCPU
2–4 vCPU
RAM
2 GB
4 GB
Datenträger
15 GB SSD
20–40 GB SSD
Betriebssystem
Linux (x86-64 oder ARM64) mit Docker Engine (≥ 24) + Docker Compose v2 (docker compose)
dito
Einordnung der Komponenten (Anhaltswerte im Leerlauf): PostgreSQL ~150 MB, Redis ~30 MB, Backend (Python/uvicorn inkl. Add-ons) ~300 MB, Frontend ~300 MB, Caddy ~40 MB. Spitzen entstehen kurzfristig bei PDF-Erzeugung, KI-Aufrufen und großen Versand-Batches.
Hinweise:
Minimum genügt für kleinere Organisationen (bis einige Hundert Empfänger, gelegentliche Kampagnen).
Empfohlen gibt Reserve für größere Kampagnen, Reporting/KI und die mit jeder Kampagne wachsenden Tracking-Daten.
Eine SSD wird für die Datenbank empfohlen (viele kleine Schreibvorgänge durch Tracking-Ereignisse).
Netzwerk: ausgehender SMTP-Zugang (Versand) und Erreichbarkeit der APP_DOMAIN für die Zielpersonen (Tracking).
Optionaler GeoIP-Länder-Lookup benötigt eine lokale MMDB-Datei (~10–60 MB, siehe Konfiguration).
Die interaktive Installationsroutine führt dich durch alle wichtigen Einstellungen, erzeugt eine gültige .env aus .env.example, generiert sichere Secrets (SECRET_KEY, DB-Passwort) und hält DATABASE_URL automatisch synchron. Sie ist zweisprachig (Deutsch/Englisch).
Repository klonen — holt den kompletten Stack (Code, install.sh, docker-compose.yml, .env.example) von GitHub auf den Server:
Terminal-Fenster
# Falls Git noch fehlt (Debian/Ubuntu):
sudoaptinstall-ygit
# In ein Verzeichnis deiner Wahl wechseln, z. B. /opt:
cd/opt
# Repository klonen — erzeugt den Unterordner "sentrymail":
# In den neuen Ordner wechseln — hier laufen alle weiteren Befehle:
cdsentrymail
Hinweise:
Nach dem Klonen liegt der aktuelle Stand des main-Branch vor. Wer eine bestimmte Version betreiben möchte, checkt den zugehörigen Release-Tag aus, z. B. git checkout v0.15.0 (verfügbare Versionen: GitHub → Releases).
Updates später im selben Ordner mit git pull holen, danach den Stack mit docker compose up -d --build neu bauen/starten.
Ohne Git geht es auch: auf der GitHub-Seite über Code → Download ZIP herunterladen und entpacken. Der bequeme Update-Weg über git pull entfällt dann allerdings.
Routine starten:
Terminal-Fenster
./install.sh
⚠️ Liegt das Installationsverzeichnis an einem Ort, an dem dein Benutzer keine Schreibrechte hat (z. B. unter /opt), muss die Routine mit Root-Rechten laufen: sudo ./install.sh. Ohne Root-Rechte schlagen Installation und spätere Updates dort mit Permission-Fehlern fehl.
Die Routine schreibt ausschließlich in die .env (Rechte 600) — es wird nichts im Code fest verdrahtet. Eine bestehende .env kann auf Wunsch als Basis weiterverwendet werden.
docker compose up -d startet den Produktionsbetrieb. Das ist die Vorgabe und für jede echte Installation die richtige Wahl:
Das Frontend wird beim Bauen zu statischen Dateien kompiliert und im Container von einem schlanken Webserver ausgeliefert — es läuft kein Vite-Devserver.
Weder der Backend- noch der Frontend-Port wird auf dem Host veröffentlicht. Erreichbar ist der Stack ausschließlich über caddy (80/443).
Der Quelltext wird nicht in die Container gemountet, das Backend läuft ohne --reload. Jede Code-Änderung wird erst durch einen Neubau wirksam (siehe Update).
Für die Entwicklung kommt docker-compose.dev.yml dazu — Vite mit Hot Reload, uvicorn --reload, Quelltext als Bind-Mount und die direkt veröffentlichten Ports 5173 (Dashboard) und 8000 (API):
⚠️ Der Entwicklungs-Stack gehört nicht auf eine Maschine, die aus dem Internet erreichbar ist. Der Vite-Devserver liefert den gesamten Frontend-Quelltext unauthentifiziert aus und meldet jeden serverseitigen Ladefehler per HMR-WebSocket an alle verbundenen Browser — auch Fehler, die ein fremder Portscanner ausgelöst hat. Die Ports 5173/8000 hören deshalb nur auf 127.0.0.1. DEV_BIND_ADDRESS ist nur für den Fall gedacht, dass ein anderer Rechner im vertrauenswürdigen Netz zugreifen muss — dort niemals eine öffentlich erreichbare Adresse eintragen.
Vite setzt die VITE_*-Werte beim Bauen fest in die ausgelieferten Dateien ein. Im Produktionsbetrieb wirkt eine Änderung in der .env deshalb erst nach einem Neubau des Frontends:
Terminal-Fenster
dockercomposebuildfrontend && dockercomposeup-d
Im Entwicklungs-Stack liest der Devserver dieselben Werte zur Laufzeit; dort genügt docker compose up -d.
Auf welchen Schnittstellen das Dashboard antwortet
Ohne weitere Angabe lauscht caddy auf allen Netzwerkschnittstellen der Maschine (0.0.0.0). Bei einem Server mit öffentlicher IP heißt das: im Internet erreichbar — auch dann, wenn der Zugriff eigentlich nur über ein VPN gedacht war. FRONTEND_BIND_ADDRESS begrenzt das auf eine Schnittstelle; hinein gehört deren IP-Adresse (ip -4 addr show listet sie auf), z. B. die des VPN-/Overlay-Interfaces:
.env
FRONTEND_BIND_ADDRESS=100.64.0.5
⚠️ Hier nicht127.0.0.1 eintragen: dann antwortet das Dashboard nur noch lokal auf dem Server selbst und ist auch über das VPN nicht mehr erreichbar.
Beim ersten Start wird aus INITIAL_ADMIN_EMAIL / INITIAL_ADMIN_PASSWORD ein Admin-Konto angelegt. Danach weitere Konten über Benutzer verwalten und das Start-Passwort ändern.
Die .env und deine Daten (Datenbank-Volume) bleiben bei einem Update erhalten — aktualisiert wird nur der Code. Datenbank-Migrationen laufen automatisch beim Start des Backends; ein separater Migrationsbefehl ist nicht nötig.
Die Routine update.sh fasst alle Schritte in der richtigen Reihenfolge zusammen: Voraussetzungen prüfen → optionales DB-Backup → Code per git aktualisieren (Branch oder fester Release-Tag) → Stack neu bauen/starten → Health-Check. Sie ist zweisprachig und verändert die .env nicht.
Terminal-Fenster
cd/opt/sentrymail# dein Installationsverzeichnis
gitpull# holt auch die neueste update.sh selbst
./update.sh
💡 Beim allerersten Mal ist update.sh evtl. noch nicht vorhanden — dann einmal git pull ausführen, danach steht das Skript bereit.
⚠️ Gehört das Installationsverzeichnis root (z. B. unter /opt), müssen git pull und die Routine mit Root-Rechten laufen: sudo git pull && sudo ./update.sh — sonst bricht das Update mit Permission-Fehlern ab.
💡 Der Dump enthält die Datenbank, nicht die vom Backend abgelegten Dateien. Wer Schulungsvideos lokal speichert (LMS_STORAGE_BACKEND=filesystem, Enterprise), sichert zusätzlich das Volume backend_data:
# oder eine feste Version: git fetch --tags && git checkout v0.15.0
Stack neu bauen und starten (Migrationen laufen dabei automatisch):
Terminal-Fenster
dockercomposeup-d--build
--build ist im Produktionsbetrieb nicht optional: Backend- und Frontend-Code stecken im Image, ein bloßes up -d oder restart startet weiterhin den alten Stand. Dasselbe gilt für geänderte VITE_*-Werte in der .env (siehe Betriebsarten).
Nur im Entwicklungs-Stack (docker-compose.dev.yml) werden reine Code-Änderungen durch Bind-Mount und --reload sofort übernommen; neue Migrationen und geänderte Abhängigkeiten (requirements.txt, package.json) greifen aber auch dort erst nach up -d --build.
Läuft nach dem Update etwas nicht, auf die vorherige Version zurückwechseln (git checkout <vorheriger-Tag> bzw. git log), Stack mit docker compose up -d --build neu starten und bei Bedarf das zuvor erzeugte Backup einspielen:
⚠️ Ein zurückgespieltes Backup passt nur zu einem Code-Stand mit demselben oder älteren Migrations-Schema. Beim Downgrade daher immer erst den Code zurücksetzen, dann das Backup einspielen.
Die Business- und Enterprise-Add-ons haben eigene Releases (getrennt vom Core) und sind nicht Teil des Backend-Images. Sie werden beim Start des Backends bezogen — über den Lizenzserver, anhand deines Lizenzschlüssels. Der Neustart nach dem Update holt dabei automatisch die jeweils neueste freigeschaltete Fassung. Einzelheiten unter Lizenz & Add-ons.
Die kostenpflichtigen Business- und Enterprise-Add-ons sind eigene Python-Pakete. Sie stecken nicht im Backend-Image, sondern werden bei jedem Start des Containers bezogen: Das Backend legt seinen Lizenzschlüssel beim Lizenzserver vor, dieser prüft die Berechtigung, lädt das Paket und reicht es durch. Deine Installation braucht dafür keine Zugangsdaten zu einer Paketquelle.
Im Regelbetrieb gibt es dabei nichts zu tun: docker compose up -d --build startet den Container neu, und der Bezug läuft dabei mit. Ist die installierte Fassung bereits die aktuelle, wird nichts übertragen.
Zwei Punkte, die dir Fehlersuche ersparen:
Ohne Lizenzschlüssel passiert nichts — die Installation startet im Open-Core-Umfang. Das ist kein Fehler, sondern der Regelfall bei einer Installation ohne Add-on.
Ein fehlgeschlagener Bezug hält den Start nicht auf. Ist der Lizenzserver nicht erreichbar, startet SentryMail trotzdem und vermerkt es im Protokoll. Prüfen mit docker compose logs backend | grep -i addons.
Welche Funktionen freigeschaltet sind, entscheidet die Lizenz — nicht die Installation. Kauf, Aktivierung und Fehlerbehebung stehen unter Lizenz & Add-ons.
⚠️ Nur im Entwicklungs-Stack: Sind die Add-on-Repos per Volume in den Container gemountet, überwacht uvicorn --reloadnur das App-Verzeichnis — nicht die eingehängten Pakete. Änderungen am Add-on-Code (neue Routen, Felder usw.) werden daher erst nach einem manuellen Neustart aktiv:
Terminal-Fenster
dockercomposerestartbackend
Symptom bei vergessenem Neustart: Das Frontend ruft eine neue Add-on-Route auf, die im laufenden Prozess noch nicht existiert (HTTP 404) und zeigt eine generische Fehlermeldung. Nach dem Neustart ist die Route verfügbar.
Öffnungs-/Klick-Tracking funktioniert nur, wenn Empfänger die unter APP_DOMAIN gesetzte Adresse erreichen können. Bei rein internen/VPN-Domains registrieren externe Empfänger keine Events. Viele Mail-Clients blockieren zudem das Öffnungs-Pixel — Klicks sind daher das verlässlichere Signal.