No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-02 19:47:32 +00:00
.idea feat(zitadel): add central login (IdP) stack template 2026-06-26 08:03:53 +02:00
configs fix(zitadel): provision SMTP via DefaultInstance instead of FirstInstance 2026-06-26 10:18:20 +02:00
.env fix(zitadel): provision SMTP via DefaultInstance instead of FirstInstance 2026-06-26 10:18:20 +02:00
.gitignore feat(zitadel): add central login (IdP) stack template 2026-06-26 08:03:53 +02:00
AGENTS.md feat(zitadel): add central login (IdP) stack template 2026-06-26 08:03:53 +02:00
CLAUDE.md feat(zitadel): add central login (IdP) stack template 2026-06-26 08:03:53 +02:00
docker-compose.yml fix(zitadel): provision SMTP via DefaultInstance instead of FirstInstance 2026-06-26 10:18:20 +02:00
LICENSE chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:32:38 +02:00
Projekt.md feat(zitadel): add central login (IdP) stack template 2026-06-26 08:03:53 +02:00
README.md chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:32:38 +02:00

Zitadel – Zentraler Login / IdP (Stack-Template)

Selbst gehostete Identity-Plattform (OIDC) auf dem Hetzner-Server. Stellt einen einzigen, zentralen Login https://login.example.com bereit, den interne und externe Mandanten (IHR_PROJEKT, MANDANT_2) nutzen. TLS macht das vorhandene zentrale Traefik, Zitadel laeuft als reiner Service dahinter.

Template-Hinweis: Dieses Repo enthaelt nur Platzhalter (CHANGE_ME, example.com). Vor dem Produktiveinsatz alle Platzhalter in der .env und configs/firstinstance.yaml ersetzen.


1. Voraussetzungen

  • Docker + Docker Compose v2 auf dem Hetzner-Server

  • Das zentrale Traefik laeuft dort bereits (Entrypoints web-http/websecure-https, certresolver letsEncrypt, Middlewares redirect-to-https@file / security-headers@file)

  • Das externe Docker-Netz existiert:

    docker network create traefik_proxy_network   # falls noch nicht vorhanden
    
  • DNS-A-Record zeigt auf die oeffentliche Hetzner-IP:

    login.example.com  ->  <oeffentliche Hetzner-IP>
    

2. Einrichtung (Schritt fuer Schritt)

  1. .env anpassen (alle Platzhalter ersetzen):

    • ZITADEL_EXTERNALDOMAIN / HOSTRULE → eure Login-Domain

    • ZITADEL_MASTERKEY → 32-Zeichen-Key:

      openssl rand -base64 32 | tr -d '+/=' | cut -c1-32
      
    • PG_PASSWORD → sicheres Passwort: openssl rand -base64 24

    • SMTP (SMTP_HOST, SMTP_USER, SMTP_PASSWORD, SMTP_FROM, SMTP_FROMNAME, SMTP_TLS) → Daten des Mailproviders. Siehe Abschnitt SMTP unten.

  2. configs/firstinstance.yaml anpassen: Org-Name (= erster Mandant), Admin-Email und initiales Password setzen.

  3. Image-Tag pinnen: in docker-compose.yml die aktuelle stable eintragen (https://github.com/zitadel/zitadel/releases).

  4. Starten:

    docker compose up -d
    

    Der Ordner volumes/ wird beim ersten Start automatisch erstellt (ist in .gitignore – kommt niemals ins Git).

  5. Logs pruefen – erwartete Erfolgsmeldung:

    docker logs zitadel --tail 30
    
    TLS enabled      : false
    External Secure  : true
    Console URL      : https://login.example.com/ui/console
    server is listening on [::]:8080
    

3. Echten Admin-Login ermitteln (wichtig!)

Zitadel baut den Login-Namen nicht aus UserName@ExternalDomain, sondern aus UserName@<org-domain-aus-org-namen>.<ExternalDomain>. Den exakten Namen niemals raten, sondern direkt aus der DB holen:

docker exec zitadel-db psql -U zitadel -d zitadel \
  -c "SELECT user_id, login_name, is_primary FROM projections.login_names3;"

Beispiel: aus Org IHR_PROJEKT + Domain login.example.com wird:

admin@ihr-projekt.login.example.com

Erster Login: https://login.example.com/ui/console mit diesem Namen und dem in firstinstance.yaml gesetzten Passwort. Wegen PasswordChangeRequired: true fordert Zitadel sofort zur Passwortaenderung auf (danach 2FA einrichten).


4. Worauf besonders achten (Stolpersteine)

  • gRPC / h2c: Der Traefik-Service muss auf scheme=h2c stehen (ist gesetzt). Ohne das laedt zwar die Login-Seite, aber die Console haengt.
  • --tlsMode external: Pflicht, weil Traefik TLS terminiert. Ohne TLS-Mode bricht Zitadel mit "TLS is enabled: please specify a key/cert or disable TLS" ab. disabled waere falsch (dann erzeugt Zitadel http-URLs hinter https-Traefik).
  • --steps /firstinstance.yaml muss im command stehen und der Volume-Mount aktiv sein, sonst legt Zitadel den Default-Admin (zitadel-admin) an.
  • ExternalDomain ist im Issuer eingebrannt. Nachtraeglich aendern = Re-Init.
  • SMTP nur an DefaultInstance, nicht FirstInstance. SMTP in firstinstance.yaml wird ignoriert. Siehe Abschnitt SMTP.

SMTP / Mailversand

Zitadel braucht SMTP fuer Verifizierungs-, Einladungs- und Passwort-Mails. Ohne Config scheitert jede Mail mit Errors.SMTPConfig.NotFound.

Wichtig: SMTP laesst sich nur an DefaultInstance vorkonfigurieren, nicht an FirstInstance. Deshalb erfolgt die Konfiguration ueber Env-Variablen (ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_* in docker-compose.yml), die Werte stehen in der .env (SMTP_*).

  • Greift nur beim allerersten Start (leere DB). Bei bestehender Instanz: Console → Default Settings → Notifications → SMTP Settings.
  • SMTP_FROM und SMTP_FROMNAME muessen gesetzt sein (leer = Init-Fehler, vgl. https://github.com/zitadel/zitadel/issues/7009).
  • SMTP_TLS=true → implizites TLS (Port 465); false → STARTTLS (Port 587).
  • SMTP_HOST immer mit Port, z. B. smtp.provider.de:587.
  • Fuer Zustellbarkeit am Absender-Domain SPF/DKIM hinterlegen (sonst Spam).

Nach dem Start pruefen, ob der Mail-Kanal sauber initialisiert wurde:

docker logs zitadel 2>&1 | grep -i smtp

5. Re-Init (kompletter Neuaufbau)

docker compose up -d bei laufendem Container startet ihn nur neu, durchlaeuft aber start-from-init nicht erneut. Fuer einen sauberen Neuaufbau die DB zuruecksetzen:

docker compose down
sudo rm -rf volumes/db          # DB-Datenverzeichnis leeren
docker compose up -d

6. OIDC-Clients anbinden (spaeter)

Pro Anwendung (cf-review, Metabase, NocoDB, n8n, ...) in der jeweiligen Org eine Application anlegen und dort Issuer, Client-ID/Secret und die Redirect-URIs hinterlegen. Der Issuer ist fuer alle identisch:

https://login.example.com

7. Nuetzliche Befehle

docker compose config -q          # Konfiguration validieren (.env-Aufloesung)
docker compose up -d              # Starten
docker compose logs -f zitadel    # Live-Logs
docker compose down               # Stoppen

Lizenz

Copyright (C) 2026 Christian Säum – web-seo-consulting.eu

Dieses Projekt steht unter der GNU Affero General Public License, Version 3 oder (nach deiner Wahl) einer späteren Version (AGPL-3.0-or-later). Der vollständige Lizenztext steht in der Datei LICENSE.

Du darfst die Software nutzen, weitergeben und – auch kommerziell – verkaufen. Gibst du eine veränderte Fassung weiter oder betreibst du sie über ein Netzwerk (z. B. als Dienst), muss deren vollständiger Quellcode ebenfalls unter der AGPL-3.0-or-later verfügbar sein. Der Copyright-Hinweis und die Nennung des ursprünglichen Autors dürfen nicht entfernt werden.

Diese Angabe betrifft nur die in diesem Repository enthaltenen eigenen Dateien (Konfiguration, Skripte, Anpassungen). Eingebundene Fremdsoftware und Container-Images unterliegen weiterhin ihren eigenen Lizenzen.