Docker Compose ist der schnellste Weg, eine Sannvit-Ledger-Instanz zu betreiben — egal ob als lokale Entwicklungsumgebung oder als Single-Host-Produktions-Deployment. Im Folgenden wird davon ausgegangen, dass Sie das Repository bereits geklont haben.
Der Stack ist in eine Basisdatei plus Overrides aufgeteilt, die Sie nach Bedarf hinzufügen:
| Service | Compose-Datei | Was es ist |
|---|---|---|
db | docker-compose.yml | Einfaches postgres:17 — die einzige Datenbank im Stack |
keycloak | docker-compose.keycloak.yml | Authentifizierung — Direct Access Grant, keine gehostete Login-UI |
api / alerting | docker-compose.api.yml | Der Ingest-Service, plus sein eigenständiger Integritäts-/Alerting-Runner als zweiter Container |
dashboard | docker-compose.dashboard.yml | Die Browser-UI |
rustfs | docker-compose.rustfs.yml | Gebündelter S3-kompatibler Blob Store — optional, siehe Eigenen S3-kompatiblen Speicher verwenden |
mail | docker-compose.mail.yml | SMTP-Abfangdienst nur für die Entwicklung (Mailpit), damit Einladungs-/Reset-/Alert-E-Mails sichtbar landen |
nginx / caddy | docker-compose.nginx.yml / docker-compose.caddy.yml | Optionaler TLS-terminierender Reverse Proxy vor den Subdomains app. / api. / auth. |
Die App spricht direkt mit einfachem Postgres, und Keycloak übernimmt die Authentifizierung — ohne zusätzliche Services dazwischen — was den Footprint klein genug hält, um auf der eigenen Infrastruktur eines Kunden installiert zu werden.
.env liegt im Repository-Root und wird von jeder Compose-Datei gelesen.
cp .env.example .env
Füllen Sie mindestens diese Secrets aus, bevor Sie irgendetwas starten — openssl rand -hex 24 für jedes:
POSTGRES_PASSWORDJWT_SECRETKEYCLOAK_ADMIN_PASSWORDKEYCLOAK_SERVICE_CLIENT_SECRETS3_ROOT_PASSWORD (nur nötig, wenn Sie den gebündelten Blob Store verwenden)EXPORT_SECRET_KEY (nur nötig, bevor Sie das SFTP-Export-Feature für Nachweispakete nutzen)Für die lokale Arbeit reichen reine Entwicklungswerte — verwenden Sie diese nur nirgendwo produktiv weiter.
docker/run.sh verwaltet, welche Compose-Override-Dateien aktiv sind, und liest .env immer aus dem Repository-Root, unabhängig vom Arbeitsverzeichnis Ihrer Shell:
cd docker
./run.sh config add keycloak rustfs mail api api.dev dashboard dashboard.dev
./run.sh start
api.dev / dashboard.dev legen Hot-Reload (bind-gemounteter Quellcode, tsx watch / Nuxt HMR) über ihre jeweiligen Basisservices.
npm run prod
was äquivalent ist zu:
cd docker
COMPOSE_FILE=docker-compose.yml:docker-compose.keycloak.yml:docker-compose.rustfs.yml:docker-compose.api.yml:docker-compose.dashboard.yml \
COMPOSE_ENV_FILES=../.env COMPOSE_IGNORE_ORPHANS=true \
docker compose up -d --wait --build
!WARNING Bevor Sie das im Ernstfall tun:
- Die Werte in
.env.examplesind Platzhalter, keine Secrets — setzen Sie für jeden oben genannten Eintrag echte, eindeutige Werte.- Stellen Sie einen echten TLS-terminierenden Reverse Proxy davor (
docker-compose.nginx.ymloder.caddy.yml), anstatt rohe Service-Ports offenzulegen, und setzen SiePROXY_DOMAINin.env.- Ändern Sie das Client-Secret von Keycloaks
ledger-servicegegenüber dem Entwicklungs-Default aus dem Realm-Export (docker/volumes/keycloak/ledger-realm.json) über die Keycloak-Admin-Konsole und aktualisieren SieKEYCLOAK_SERVICE_CLIENT_SECRETin.enventsprechend.- Richten Sie
SMTP_*auf ein echtes Relay statt auf Mailpit, und setzen SieDASHBOARD_URLauf die echte öffentliche Dashboard-Domain — siehe E-Mail (SMTP) unten.- Richten Sie ordentliche Backup-Verfahren für das
db-Volume ein.
Dies ist ein einmaliger Schritt pro frischer Datenbank — nicht Teil von run.sh start. Warten Sie, bis db und keycloak als healthy gemeldet werden (./run.sh status), dann vom Repository-Root aus:
for f in api/drizzle/0*.sql; do
psql -h localhost -U postgres -d postgres -v ON_ERROR_STOP=1 -f "$f"
done
cd api
npm install
npm run db:functions # wendet src/db/functions/*.sql an — keine drizzle-kit-Objekte
npm run seed:demo # Demo-Org + Team + Ingest-Key (Key wird einmal ausgegeben, aufbewahren)
Es gibt keinen vorab angelegten Dashboard-Benutzer — seed:demo legt nur eine Demo-Org/-Team/-Ingest-Key für die SDK-Seite an. Um einen menschlichen Login zu erhalten, bootstrappen Sie stattdessen den ersten Admin (aus api/, sobald db und keycloak laufen und die Migrationen angewendet sind):
npm run seed:admin -- you@example.com --org-name="Your Org Name"
Dies gibt einmalig ein generiertes Passwort aus. Jeder weitere Benutzer wird über das Dashboard eingeladen (Organization → Users → Invite) durch einen bestehenden compliance_admin, nicht über dieses Script.
http://localhost:3000http://localhost:4010 (GET /healthz)http://localhost:8180http://localhost:8025http://localhost:9001 (gebündeltes RustFS, falls beibehalten)run.sh-Befehle./run.sh logs [service] # Logs verfolgen
./run.sh status # docker compose ps
./run.sh recreate [service] # einzelnen Service neu erstellen
./run.sh stop # alles stoppen
Wenn Sie docker compose direkt statt run.sh aufrufen, muss die Env-Datei explizit angegeben werden, z. B. vom Repository-Root aus:
docker compose --env-file .env -f docker/docker-compose.yml -f docker/docker-compose.keycloak.yml up -d
Standardmäßig bündelt der Stack einen RustFS-Container als Blob Store für Payload-Inhalte — das Ledger selbst speichert nur einen Zeiger + Hash. Wenn Sie lieber auf einen bestehenden Bucket zeigen möchten (AWS S3, Cloudflare R2, Backblaze B2, eigenes MinIO/RustFS usw.):
rustfs-Override nicht hinzu — überspringen Sie ./run.sh config add rustfs, oder führen Sie ./run.sh config remove rustfs aus, falls er bereits vorhanden ist..env S3_ENDPOINT, S3_PORT, S3_USE_SSL und optional S3_REGION auf den externen Provider sowie S3_ACCESS_KEY / S3_SECRET_KEY auf Zugangsdaten, die auf diesen Bucket beschränkt sind. Setzen Sie LEDGER_BUCKET auf den Bucket-Namen.CreateBucket.Die append-only zweite Integritätsebene ist ein zweiter Bucket (LEDGER_INTEGRITY_BUCKET, Standard ledger-integrity) auf demselben Endpoint, angelegt mit aktiviertem S3 Object Lock — unlöschbar für sein Aufbewahrungsfenster, selbst für Admins.
!CAUTION Der gebündelte RustFS-Container hat bekannte Bugs in seiner Object-Lock-Implementierung. Für die Entwicklung ist das unproblematisch, aber Produktions-Deployments sollten
LEDGER_INTEGRITY_BUCKETüber den Bring-your-own-S3-Weg auf eine ausgereifte Object-Lock-Implementierung richten — echtes AWS S3, Backblaze B2 oder GCS über S3-Interop.
Die Ledger API versendet Einladungs-, Passwort-Reset- und Alert-Digest-E-Mails per SMTP.
Lokale Entwicklung — E-Mails abfangen statt versenden:
./run.sh config add mail
./run.sh start
Jede E-Mail landet unter http://localhost:8025 (Mailpit) statt in einem echten Postfach.
Produktion — echte E-Mail zustellen:
SMTP_ADMIN_EMAIL, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS und SMTP_SENDER_NAME in der .env dieser Umgebung. Lassen Sie SMTP_ALLOW_INSECURE_AUTH unset — es existiert nur für Mailpit.DASHBOARD_URL auf die echte öffentliche Dashboard-Domain — sie wird in Einladungs-/Reset-E-Mail-Links eingebettet.mail-Override in der Produktion nicht hinzu, sonst fängt er echte Mail ab../run.sh recreate api alerting.Wenn Ihr Provider eine Domain-Verifizierung erfordert (SPF/DKIM, Absenderidentität — üblich bei SES und Postmark), muss das auf Seiten des Providers abgeschlossen sein, bevor Mail tatsächlich zugestellt wird.
docker-compose.*.yml.docker compose pull.api / dashboard neu, falls sich deren Quellcode geändert hat: docker compose -f docker-compose.api.yml -f docker-compose.dashboard.yml up -d --build.Sichern Sie Ihre Datenbank vor jedem Update.
Für ein Cluster-Deployment über einen einzelnen Compose-Host hinaus gibt es einen Helm-basierten Kubernetes-Weg — Images bauen/pushen, Secrets, DNS und helm install — getrennt von Docker Compose behandelt.
Erste Schritte
Bringen Sie Ihre eigene Sannvit-Ledger-Instanz zum Laufen — von einem frischen Checkout bis zu einer funktionierenden Audit-Chain.
Hosting auf Kubernetes
Deployen Sie das Sannvit Ledger mit dem Helm-Chart auf den Kubernetes-Cluster eines Kunden, für horizontale Skalierung über einen einzelnen Host hinaus.