Krywerk Server betreiben¶
Anleitung für Betreiber (IT-Administration einer Organisation oder eines Dienstleisters): Installation, Anmeldedienst, Sicherung, Updates, Überwachung, Datenschutz. Stand F8 (2026-10-14).
Krywerk Server ist der Schlüsselserver für Team-Ordner: Er verteilt die verschlüsselten Tresorschlüssel an berechtigte Personen und Geräte. Er ist kompatibel mit den Cryptomator-Apps (Hub-Protokoll) und mit der Krywerk-App. Die Dateien selbst liegen nicht auf dem Server, sondern im Cloud-Speicher der Organisation (OneDrive, SharePoint, Nextcloud …).
Krywerk-App / Cryptomator-App ──HTTPS──▶ Reverse Proxy (Caddy) ──▶ krywerk-server ──▶ SQLite (/data)
│ │
└──── Anmeldung im Browser (OIDC) ──▶ Keycloak ──(optional)──▶ Entra ID / anderer Anbieter
└──── verschlüsselte Dateien ───────▶ Cloud-Speicher (OneDrive, …)
1. Was der Server speichert – und was nicht¶
| Gespeichert (SQLite-Datei) | Nie auf dem Server |
|---|---|
| Nutzer: ID aus dem Anmeldedienst, Anzeigename, E-Mail, Vor-/Nachname | Passwörter (Anmeldung macht der Anmeldedienst) |
| Gruppen aus dem Token (Name, Mitgliedschaften) | Masterkeys der Tresore im Klartext |
| öffentliche Schlüssel, verschlüsselte private Schlüssel der Nutzer | Freischaltcodes (Account Keys) |
| Geräte: Name, Typ, öffentlicher Schlüssel, letzter Zugriff, letzte IP-Adresse | Dateien, Dateinamen, Inhalte |
| Team-Ordner: Name, Beschreibung, Mitglieder/Rollen, Archiv-Status | |
| Freigaben: Tresorschlüssel, verschlüsselt für jede berechtigte Person |
Wer nur die Datenbank besitzt, kann keinen Team-Ordner entschlüsseln: Dafür braucht es zusätzlich den Freischaltcode bzw. einen freigeschalteten Geräteschlüssel einer berechtigten Person. Trotzdem ist die Datenbank vertraulich (Mitgliederlisten, E-Mail-Adressen, IP-Adressen) – Sicherungen entsprechend schützen.
Das Zugriffsprotokoll (Standardausgabe) enthält Zeit, Methode, Pfad (mit Tresor- bzw. Geräte-ID) und Status –
nie Tokens, Schlüssel, Header oder Inhalte. Abschalten mit KRYWERK_SERVER_QUIET=1.
2. Voraussetzungen¶
- Linux-Server (oder VM) mit Docker Engine ≥ 24 und Compose-Plugin; 1 vCPU und 512 MB RAM genügen für den Server, mit eigenem Keycloak eher 2 GB RAM.
- Ein DNS-Name für den Schlüsselserver, z. B.
schluessel.example.org, mit eigenem Keycloak ein zweiter, z. B.login.example.org. Ports 80 und 443 von außen erreichbar (Let's Encrypt). - Ein Anmeldedienst (OIDC). Empfohlen: Keycloak – vorhanden oder über
compose.keycloak.yamlmitgeliefert. Konten aus Microsoft Entra ID (Microsoft 365) oder einem anderen Anbieter werden dort angebunden (Abschnitt 4).
Warum nicht direkt Entra ID? Die offizielle Cryptomator-Desktop-App meldet sich über eine Loopback-Adresse mit zufälligem Pfad an (
http://127.0.0.1:<Port>/<zufällig>). Entra ID verlangt nach unserem Kenntnisstand, dass der Pfad registriert ist, und lehnt solche Anmeldungen ab; außerdem senden die Apps keinenscope. Keycloak erlaubt beliebige Loopback-Ports und Pfade (RFC 8252) und dient als Broker vor Entra ID – so macht es auch der Cryptomator Hub. Siehe Abschnitt 5 für die experimentelle Direktanbindung.
3. Installation mit Docker (empfohlen)¶
Die Dateien liegen in crates/kw-server/deploy/:
| Datei | Zweck |
|---|---|
compose.yaml |
Krywerk Server + Caddy (automatisches TLS über Let's Encrypt) |
compose.keycloak.yaml |
Ergänzung: eigener Keycloak mit Postgres |
Caddyfile, Caddyfile.keycloak |
Reverse Proxy (HSTS, Sicherheits-Header; Keycloak-Verwaltung nur aus internen Netzen) |
keycloak/realm-krywerk.json |
Realm-Vorlage: Client cryptomator, Rollen, Gruppen-Claim |
krywerk.env.example |
Einstellungen des Servers |
backup.sh, restore.sh |
Sicherung und Wiederherstellung |
krywerk-server.service, krywerk-server.toml |
Betrieb ohne Docker (Abschnitt 6) |
3.1 Image¶
Ohne Registry wird das Image auf dem Server aus dem Quellcode gebaut (Rust-Toolchain im Build-Container, ~1 min):
git clone <repo> /opt/krywerk && cd /opt/krywerk/crates/kw-server/deploy
docker compose build
Das Image (ghcr.io/mzilinski/krywerk-server:<Version>, lokal gebaut krywerk-server) enthält nur das Programm und CA-Zertifikate, läuft als Nutzer ohne Rechte
(UID 10001), mit nur lesbarem Dateisystem; Daten liegen im Volume data (/data). Eigene CAs (z. B. ein
interner Keycloak mit eigener CA): Zertifikatsdatei einbinden und SSL_CERT_FILE=/pfad/ca.pem setzen.
3.2 Mit eigenem Keycloak¶
cp krywerk.env.example krywerk.env # Variante A ist voreingestellt: Domains anpassen
cat > .env <<EOF
KRYWERK_DOMAIN=schluessel.example.org
KEYCLOAK_DOMAIN=login.example.org
KEYCLOAK_ADMIN_PASSWORD=$(openssl rand -base64 24)
KEYCLOAK_DB_PASSWORD=$(openssl rand -base64 24)
EOF
chmod 600 .env
alias kc='docker compose -f compose.yaml -f compose.keycloak.yaml'
kc up -d # erster Start ~1 min (Realm-Import)
kc run --rm server check # Konfiguration + Anmeldedienst prüfen
krywerk.env (Variante A): KRYWERK_SERVER_OIDC_ISSUER=https://login.example.org/realms/krywerk und
KRYWERK_SERVER_OIDC_INTERNAL_URL=http://keycloak:8080/realms/krywerk (Discovery/JWKS intern; die Apps bekommen
trotzdem die öffentlichen Adressen).
Danach in Keycloak (https://login.example.org/admin/, Benutzer admin, Passwort aus .env; die Konsole ist nur
aus privaten Netzen erreichbar – Regel in Caddyfile.keycloak anpassen):
- Realm krywerk wählen. Konten anlegen oder einen Identitätsanbieter anbinden (Abschnitt 4).
- Rollen: jeder Nutzer hat
user(Standardrolle). Wer Team-Ordner anlegen darf: Rollecreate-vaults(am besten über eine Gruppe, z. B. „Team-Ordner anlegen“ → Role mapping).admindarf alle Team-Ordner ansehen und archivieren. - Gruppen: Gruppen in Keycloak erscheinen in den Apps zum Teilen (Claim
groups, voller Pfad,/Bereich/Teamwird zu verschachtelten Gruppen). Eine Gruppe kennt der Server, sobald sich ein Mitglied einmal angemeldet hat.
3.3 Mit vorhandenem Keycloak¶
Nur compose.yaml verwenden. Im vorhandenen Realm einen Client anlegen (Werte wie in
keycloak/realm-krywerk.json): Client-ID cryptomator, öffentlich (Client authentication aus), Standard Flow an,
PKCE S256, Redirect-URIs http://127.0.0.1/*, org.cryptomator.ios:/hub/auth, org.cryptomator.android:/hub/auth,
Web Origins +; Mapper „Group Membership“ (Claim groups, Full group path an, Add to access token an); Rollen
user, create-vaults, admin als Realm-Rollen. Läuft im selben Realm ein Cryptomator Hub, den Gruppen-Claim
nicht groups nennen (der Hub liest ihn als Rollenliste → 403), sondern z. B. krywerk_groups und
KRYWERK_SERVER_GROUPS_CLAIM=krywerk_groups setzen.
3.4 Web-Verwaltung¶
Im Browser unter https://schluessel.example.org/verwaltung/: Übersicht, Team-Ordner, Personen (sperren), eigene
Gruppen, Notfallanträge, Protokoll. Einschalten mit KRYWERK_SERVER_WEB=1 in krywerk.env (Vorlage: an).
- Client
krywerk-verwaltung: Bei der Realm-Vorlage (3.2) ist er schon angelegt. Bei vorhandenem Keycloak (3.3) einen öffentlichen Client anlegen: Standard Flow, PKCE S256, Redirect-URIhttps://schluessel.example.org/verwaltung/*, Post-Logout-Redirect+, derselbe Gruppen-Mapper wie beicryptomator. - Die Rolle
adminmacht zur IT-Administration (alle Team-Ordner, Personen, Gruppen, Protokoll). Wer Team-Ordner verwaltet, sieht dort nur die eigenen. - Nur aus dem internen Netz: Die Caddy-Vorlagen sperren
/verwaltungfür öffentliche Adressen (Block@verwaltung_extern, Bereiche anpassen oder entfernen). TZ=Europe/Berlininkrywerk.envsorgt für Uhrzeiten in Ortszeit.
Einzelheiten, Sicherheit und Grenzen (z. B. „Zugriff gewähren“ bleibt in der App): docs/web-verwaltung.md.
3.5 Prüfen¶
curl https://schluessel.example.org/health # → ok
curl https://schluessel.example.org/api/config # apiLevel 4, öffentliche Anmelde-Endpunkte
Dann in der Krywerk-App „Organisationskonto → Adresse des Schlüsselservers“ eintragen und anmelden, oder mit
krywerk-hub --server https://schluessel.example.org konto-einrichten.
4. Konten aus Entra ID (Microsoft 365) über Keycloak¶
In Entra ID (Microsoft Entra Admin Center → Anwendungen → App-Registrierungen → Neue Registrierung):
- Name „Krywerk Anmeldung“, Kontotyp „Nur Konten in diesem Organisationsverzeichnis“.
- Umleitungs-URI (Web):
https://login.example.org/realms/krywerk/broker/entra/endpoint. - Zertifikate & Geheimnisse → neuer geheimer Clientschlüssel (Ablaufdatum notieren!).
- Optional Gruppen: Tokenkonfiguration → Gruppenanspruch hinzufügen → „Sicherheitsgruppen“ bzw. „Der Anwendung zugewiesene Gruppen“ (empfohlen, hält das Token klein). Entra ID liefert Objekt-IDs (GUIDs).
- Optional: Unternehmensanwendungen → „Krywerk Anmeldung“ → Eigenschaften → „Zuweisung erforderlich“ = Ja, dann nur zugewiesene Personen/Gruppen zulassen.
In Keycloak (Realm krywerk → Identity providers → „Microsoft“ oder „OpenID Connect v1.0“):
- Alias
entra, Client-ID = Anwendungs-ID, Client Secret = Schlüssel aus Schritt 3; bei „OpenID Connect“ Discovery-URLhttps://login.microsoftonline.com/<Tenant-ID>/v2.0/.well-known/openid-configuration. - „Sync mode“ = Force (Name/E-Mail bei jeder Anmeldung aktualisieren), „Trust email“ an.
- Gruppen: je Entra-Gruppe ein Mapper „Advanced Claim to Group“ (Claim
groupsenthält die GUID → Keycloak- Gruppe „Fachbereich Finanzen“ o. Ä.). Alternativ Gruppen nur in Keycloak pflegen. - Rolle
create-vaults: Mapper „Advanced Claim to Role“ für eine Entra-Gruppe oder direkt in Keycloak zuweisen. - Direkt zu Microsoft weiterleiten (ohne Keycloak-Anmeldeseite): in
krywerk.envKRYWERK_SERVER_OIDC_AUTH_ENDPOINT=https://login.example.org/realms/krywerk/protocol/openid-connect/auth?kc_idp_hint=entra– die Apps übernehmen vorhandene Query-Parameter.
Andere Anbieter (Google Workspace, landesweite Bildungs-/Verwaltungs-Logins, SAML-IdPs) bindet man in Keycloak genauso als Identity Provider an.
5. Entra ID direkt (experimentell, ungetestet)¶
Nur für Umgebungen, in denen ausschließlich die Krywerk-App genutzt wird und Keycloak nicht in Frage kommt.
Bekannte Hürden: (1) Loopback-Redirect mit zufälligem Pfad (siehe Abschnitt 2) – die offizielle Desktop-App
wird scheitern; (2) Entra ID verlangt scope – über die Query des Authorization Endpoints lösbar
(KRYWERK_SERVER_OIDC_AUTH_ENDPOINT=…/oauth2/v2.0/authorize?scope=api%3A%2F%2F<Client-ID>%2FTresore.Zugriff%20openid%20profile);
(3) Tokens ohne eigenen API-Scope sind für Microsoft Graph ausgestellt und nicht prüfbar – daher in der
App-Registrierung „Eine API verfügbar machen“ (Scope Tresore.Zugriff), Manifest accessTokenAcceptedVersion: 2,
App-Rollen Tresore.Anlegen und Krywerk.Admin; Plattform „Mobile und Desktop“ mit Redirect http://127.0.0.1.
Einstellungen: Block „Variante B“ in krywerk.env.example. Gruppen erscheinen als GUIDs; ab ~200 Gruppen
sendet Entra ID einen Überlauf-Verweis (Mitgliedschaften bleiben dann unverändert).
6. Ohne Docker (systemd)¶
cargo build --release -p kw-server # im Wurzelverzeichnis; reines Rust, kein OpenSSL
Dann wie im Kopf von deploy/krywerk-server.service beschrieben installieren (eigener Systemnutzer, Daten in
/var/lib/krywerk, Konfiguration /etc/krywerk/krywerk-server.toml, gehärtete Unit). TLS über einen Reverse
Proxy vor 127.0.0.1:8380 (Caddy: schluessel.example.org { reverse_proxy 127.0.0.1:8380 }) mit
trust_proxy = true. Sicherung: sudo -u krywerk krywerk-server --config … backup <ziel> per Timer/cron.
7. Laufender Betrieb¶
7.1 Befehle¶
| Befehl | Zweck |
|---|---|
krywerk-server check |
Konfiguration, Datenbank und Anmeldedienst prüfen (vor Start/Update) |
krywerk-server backup <ziel> |
konsistente Sicherung im laufenden Betrieb, danach geprüft (Datei 0600) |
krywerk-server verify <datei> |
Sicherung prüfen: Integrität, Schema-Version, Anzahlen (ohne Konfiguration) |
krywerk-server restore <datei\|-> [--force] |
Sicherung zurückspielen (Server muss gestoppt sein) |
krywerk-server healthcheck |
GET /health am lokalen Server (Docker-HEALTHCHECK) |
Im Docker-Betrieb mit docker compose run --rm server <befehl> bzw. docker compose exec server krywerk-server <befehl>.
7.2 Sicherung¶
Was sichern: die Datenbank des Servers (enthält alles) – mit eigenem Keycloak zusätzlich dessen Datenbank
(docker compose … exec keycloak-db pg_dump -U keycloak keycloak > keycloak.sql) – sowie krywerk.env/.env.
Die Team-Ordner selbst sichert der Cloud-Speicher.
# täglich 02:15, 30 Tage aufbewahren (crontab des Betriebsnutzers)
15 2 * * * /opt/krywerk/crates/kw-server/deploy/backup.sh /var/backups/krywerk 30 >>/var/log/krywerk-backup.log 2>&1
backup.sh nutzt docker compose im Ordner deploy/; mit Keycloak-Ergänzung vorher
COMPOSE_FILE=compose.yaml:compose.keycloak.yaml setzen. Sicherungen regelmäßig außer Haus kopieren und
mindestens vierteljährlich eine Wiederherstellung üben (krywerk-server verify auf der Kopie genügt nicht als
Übung – einmal in eine Testinstanz zurückspielen und einen Team-Ordner öffnen).
7.3 Wiederherstellen¶
./restore.sh /var/backups/krywerk/krywerk-server-<Zeit>.sqlite3
stoppt den Server, prüft die Sicherung, spielt sie zurück (bisherige Datenbank bleibt als
krywerk-server.sqlite3.vor-restore-<Zeit> im Volume) und startet neu. Folgen: Was nach der Sicherung
entstand, fehlt: neue Team-Ordner sind nicht mehr bekannt (Öffnen → „Kein Zugriff“), neu freigeschaltete Geräte
müssen erneut freigeschaltet werden, neue Freigaben erneut gewährt werden. Team-Ordner, deren Schlüssel nur auf dem
Server lagen, sind ohne Sicherung verloren – außer es gibt einen Wiederherstellungsschlüssel (F9). Deshalb:
regelmäßig sichern.
7.4 Updates¶
cd /opt/krywerk && git pull
cd crates/kw-server/deploy
./backup.sh /var/backups/krywerk 30 # vorher sichern
docker compose build && docker compose run --rm server check
docker compose up -d # Datenbank-Migrationen laufen beim Start automatisch
Ein Zurück auf eine ältere Version ist nach einer Schema-Änderung nur mit der Sicherung von vorher möglich (ältere
Server verweigern neuere Datenbanken mit einer klaren Meldung). Caddy/Keycloak/Postgres-Images regelmäßig
aktualisieren (docker compose pull && docker compose up -d; Keycloak-Hauptversionen nach dessen Upgrade-Anleitung).
7.5 Überwachung¶
GET https://schluessel.example.org/health→200 ok(Datenbank erreichbar), sonst 503. Erfolgreiche Abfragen werden nicht protokolliert.- Docker meldet den Zustand (
docker compose ps→healthy). - Protokolle:
docker compose logs -f server. Häufige 401 → Anmeldedienst/Uhrzeit prüfen; 403 → fehlende Rolle oder Freigabe (normal, wenn Personen ohne Zugriff Ordner öffnen). - Ablauf des Entra-Client-Secrets (Keycloak-Broker) im Kalender vormerken.
7.6 Fehlerbehebung¶
| Symptom | Ursache / Lösung |
|---|---|
check: „Discovery meldet issuer … statt …“ |
KRYWERK_SERVER_OIDC_ISSUER muss exakt dem iss der Tokens entsprechen (ohne / am Ende) |
check: Anbieter nicht erreichbar |
OIDC_INTERNAL_URL prüfen; Server braucht ausgehenden Zugriff zum Anbieter; eigene CA → SSL_CERT_FILE |
| Apps: „Server nicht vertrauenswürdig“ | public_url/KRYWERK_DOMAIN muss HTTPS sein; Apps akzeptieren HTTP nur für localhost |
| Alle Anfragen 401 | Uhrzeit des Servers (NTP), Issuer, ggf. OIDC_AUDIENCE falsch gesetzt; Tokens eines anderen Clients (azp) – dann OIDC_CLIENT_ID bzw. OIDC_ALLOWED_CLIENTS prüfen |
| Alle Anfragen 403 | Rolle user fehlt (Standardrolle im Realm) bzw. ROLE_USER leeren, wenn der Anbieter keine Rollen liefert |
| „Darf keine Team-Ordner anlegen“ | Rolle create-vaults zuweisen |
| Gruppe nicht auffindbar | Mitglied muss sich einmal angemeldet haben; Gruppen-Claim im Token? (GROUPS_CLAIM) |
restore: „antwortet noch“ |
Server zuerst stoppen (restore.sh macht das) |
| Web-Verwaltung: „Invalid parameter: redirect_uri“ beim Anmeldedienst | Rücksprung https://<KRYWERK_DOMAIN>/verwaltung/anmeldung am Client krywerk-verwaltung eintragen |
| Web-Verwaltung: „Sitzung abgelaufen“ bei jedem Formular | Proxy überschreibt Referrer-Policy mit no-referrer (Browser senden dann Origin: null) – in Caddy ?Referrer-Policy verwenden |
| Web-Verwaltung: 403 „nur aus dem internen Netz“ | Caddy-Block @verwaltung_extern anpassen |
| Web-Verwaltung: kein Menü „Personen“ | Rolle admin fehlt im Token (Rollen-Claim) |
8. Sicherheit und Datenschutz¶
- Härtung: nur Caddy ist von außen erreichbar; Server als Nutzer ohne Rechte, nur lesbares Dateisystem, keine Capabilities. Keycloak-Verwaltung nur intern. Updates zeitnah einspielen.
- Rollen trennen: Betreiber des Servers ≠ Mitglied aller Team-Ordner. Der Betreiber sieht Metadaten, aber keine
Inhalte. Die Rolle
adminerlaubt Ansehen/Archivieren aller Team-Ordner, aber kein Entschlüsseln. - Zugriff entziehen wirkt für künftige Abrufe; wer den Schlüssel schon einmal hatte, könnte ältere Kopien weiter entschlüsseln (Tresorformat 8 kennt keine Schlüsselrotation). Bei Austritten mit Risiko „Schlüssel erneuern“ (F10).
- DSGVO: Verarbeitung im Verzeichnis der Verarbeitungstätigkeiten aufnehmen (Zweck: Zugriffssteuerung auf
verschlüsselte Team-Ordner; Daten: siehe Abschnitt 1; Löschung: Konten verschwinden nicht automatisch, wenn sie im
Anmeldedienst gelöscht werden – derzeit manuell). Letzte IP-Adresse je Gerät wird gespeichert (Anzeige „zuletzt
benutzt“); Zugriffsprotokolle mit Docker-Log-Rotation begrenzen (
/etc/docker/daemon.json:log-optsmax-size). Protokoll (krywerk_event, Web-Verwaltung → Protokoll): wer wann Mitglieder, Geräte, Ordner geändert und Schlüssel abgerufen hat; keine Inhalte, Schlüssel oder Tokens. AufbewahrungKRYWERK_SERVER_AUDIT_RETENTION_DAYS(Standard 365 Tage), IP-Adressen nur mitKRYWERK_SERVER_AUDIT_RECORD_IP=true. Im Verzeichnis der Verarbeitungstätigkeiten aufführen; Zugriff hat nur die IT-Administration (verwaltende Personen sehen ihre Ordner). - Notfall: Ohne Datenbank und ohne Wiederherstellungsschlüssel sind Team-Ordner nicht mehr zu öffnen. Für jeden wichtigen Team-Ordner mindestens zwei verwaltende Personen und (ab F9) einen versiegelt hinterlegten Wiederherstellungsschlüssel bzw. Notfallzugriff einrichten.
9. Checkliste Inbetriebnahme¶
- [ ] DNS-Einträge, Ports 80/443, Server mit automatischen Sicherheitsupdates
- [ ] Anmeldedienst eingerichtet, Testkonto meldet sich an, Rollen
create-vaultsvergeben - [ ]
docker compose run --rm server checkohne Fehler,/health→ ok - [ ] Krywerk-App: Organisationskonto verbinden, Konto einrichten, Team-Ordner anlegen und mit Testperson teilen
- [ ] Web-Verwaltung:
/verwaltung/aus dem internen Netz erreichbar, von außen 403; Anmeldung mitadmin-Konto - [ ]
backup.shper cron, erste Sicherung geprüft (verify), Wiederherstellung in Testinstanz geübt - [ ] Docker-Log-Rotation, Überwachung von
/health, Ablaufdatum des Entra-Secrets notiert - [ ] Eintrag im Verzeichnis der Verarbeitungstätigkeiten, Information der Nutzer