Casdoor mit Docker installieren: Zentraler Auth-Server für OAuth 2.0, OIDC und SSO
Casdoor ist ein leichtgewichtiger, selbstgehosteter Auth-Server mit WebUI, der OAuth 2.0, OIDC, SAML, LDAP, WebAuthn und MFA in einem einzigen Docker-Container vereint – ideal als zentrales SSO-Gateway für heterogene App-Landschaften.

Wer mehrere Self-Hosted-Dienste betreibt – Gitea, Nextcloud, eine eigene API, ein internes Wiki – kennt das Problem: Für jeden Dienst eigene Zugangsdaten, keine zentrale Benutzerverwaltung, kein durchgängiges Single Sign-On. Casdoor löst genau das. Die in Go und React geschriebene Plattform agiert als zentraler Identity Provider (IdP) und unterstützt OAuth 2.0, OIDC, SAML, CAS, LDAP, WebAuthn, TOTP, MFA, SCIM 2.0 und RADIUS – und das mit einer vollständigen WebUI, ohne dass du eine einzige Konfigurationsdatei für die laufende Verwaltung anfassen musst. Mit über 13.800 GitHub-Stars und mehreren Releases pro Woche ist Casdoor die leichtgewichtigste Self-Hosted-Lösung mit der breitesten Protokollunterstützung am Markt. Diese Anleitung zeigt dir, wie du Casdoor mit Docker Compose und PostgreSQL auf einem beliebigen Linux-Host aufzetzt, abgesichert und verifiziert in Betrieb nimmst.
Voraussetzungen
- Docker Engine 20.10+ und Docker Compose v2.2+ (als Plugin:
docker compose, nichtdocker-compose). Falls noch nicht installiert, folge der Anleitung Docker und Docker Compose auf Linux installieren. - Linux-Host, VM oder NAS mit Docker-Unterstützung – x86_64 oder ARM64 (Raspberry Pi, Apple Silicon funktionieren nativ).
- Min. 1 CPU-Core, 512 MB RAM (empfohlen: 1 GB+), min. 2 GB freier Speicher für Image, Datenbank und Logs.
- Port 8000 vom Client erreichbar (für die WebUI); optional Port 389/636 für LDAP.
- Für HTTPS im Produktivbetrieb: Reverse Proxy (Caddy, Traefik oder Nginx) – mehr dazu in Schritt 6.
- Ein sicheres, zufälliges PostgreSQL-Passwort (min. 16 Zeichen) bereit.
Eckdaten auf einen Blick
| Eigenschaft | Wert |
|---|---|
| Docker-Image | casbin/casdoor:latest (aktuell v3.86.0, Stand Juni 2026) |
| Plattformen | linux/amd64 (~54 MB), linux/arm64 (~51 MB) |
| Webport | 8000 (konfigurierbar über httpport in app.conf) |
| Datenbank | PostgreSQL 16, MySQL 8+, SQLite (nur Test), CockroachDB, MSSQL, Oracle, TiDB |
| Protokolle | OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM 2.0, WebAuthn, TOTP, RADIUS |
| MFA-Methoden | TOTP (Authenticator-Apps), SMS, E-Mail, WebAuthn/FIDO2 |
| GitHub-Stars | 13.800+ (Stand Juni 2026) |
| Lizenz | Apache 2.0 |
| Volume / Env | Bedeutung |
|---|---|
./conf:/conf | Pflicht: Verzeichnis mit app.conf (Datenbank-Verbindung, HTTP-Port u. a.) |
./logs:/logs | Empfohlen: Casdoor-Logdateien |
postgres_data:/var/lib/postgresql/data | Pflicht für PostgreSQL: Persistenz der Datenbankdaten |
RUNNING_IN_DOCKER=true | Pflicht in Docker: ersetzt localhost im DSN automatisch durch den richtigen Container-Hostnamen |
POSTGRES_PASSWORD | Pflicht: sicheres Passwort für den PostgreSQL-Superuser |
Schritt 1: Projektordner und Verzeichnisstruktur anlegen
Lege den Projektordner an. Du kannst /opt/casdoor/ für einen systemweiten Betrieb oder ~/casdoor/ für eine Einzelnutzer-Installation verwenden.
mkdir -p /opt/casdoor/conf /opt/casdoor/logs
cd /opt/casdoorCasdoor läuft intern als Benutzer mit UID/GID 1000. Damit der Container in den logs/-Ordner schreiben darf, müssen die Berechtigungen stimmen:
chown -R 1000:1000 /opt/casdoor/conf /opt/casdoor/logsVerifizieren: Die Verzeichnisstruktur sollte so aussehen:
ls -la /opt/casdoor/
# Erwartete Ausgabe:
# drwxr-xr-x conf/ (Eigentümer: 1000)
# drwxr-xr-x logs/ (Eigentümer: 1000)Schritt 2: app.conf herunterladen und anpassen
Die zentrale Konfigurationsdatei conf/app.conf ist Pflicht – ohne sie startet Casdoor nicht. Lade die offizielle Vorlage direkt vom GitHub-Repository herunter:
curl -o /opt/casdoor/conf/app.conf \
https://raw.githubusercontent.com/casdoor/casdoor/master/conf/app.confÖffne die Datei in einem Texteditor und passe mindestens die folgenden Werte an:
; Datenbankverbindung für PostgreSQL
driverName = postgres
dataSourceName = user=casdoor password=DEIN_SICHERES_PASSWORT host=db port=5432 sslmode=disable dbname=casdoor
; HTTP-Port (muss mit dem internen Port in compose.yaml übereinstimmen)
httpport = 8000
; Deine öffentliche URL – wichtig für OIDC-Redirect-URIs
; Lokal: http://localhost:8000
; Produktion: https://auth.example.com
origin = http://localhost:8000
; Optional: Redis für Session-Caching
; redisEndpoint = redis:6379
; Optional: LDAP-Server-Funktion aktivieren
; ldapServerPort = 389Ersetze DEIN_SICHERES_PASSWORT durch dasselbe Passwort, das du gleich in der .env-Datei festlegst. Beachte das PostgreSQL-spezifische DSN-Format (Key-Value-Paare mit Leerzeichen, kein MySQL-root:pass@tcp(...)-Format).
Verifizieren: Die Datei muss für den Benutzer mit UID 1000 lesbar sein:
ls -la /opt/casdoor/conf/app.conf
# Erwartete Ausgabe: -rw-r--r-- 1 1000 1000 ...Schritt 3: .env mit Datenbankpasswort anlegen
Lege die .env-Datei an, die das PostgreSQL-Passwort enthält. Trage hier exakt dasselbe Passwort ein wie in app.conf:
# /opt/casdoor/.env
POSTGRES_PASSWORD=DEIN_SICHERES_PASSWORT_MIN16ZEICHENSchränke die Dateiberechtigungen ein, damit das Passwort nicht für andere Systembenutzer lesbar ist:
chmod 600 /opt/casdoor/.envVerifizieren:
ls -la /opt/casdoor/.env
# Erwartete Ausgabe: -rw------- 1 root root ...
# Das Passwort darf nicht leer sein:
grep POSTGRES_PASSWORD /opt/casdoor/.envSchritt 4: compose.yaml erstellen und Stack starten
Erstelle die Datei /opt/casdoor/compose.yaml mit folgendem Inhalt. Der Stack besteht aus zwei Services: dem Casdoor-Applikationscontainer und einem PostgreSQL-16-Datenbankcontainer. Der depends_on-Block mit condition: service_healthy stellt sicher, dass Casdoor erst startet, wenn die Datenbank tatsächlich bereit ist – ohne diesen Healthcheck-Mechanismus schlägt der erste Start häufig fehl, weil PostgreSQL noch initialisiert.
services:
casdoor:
image: casbin/casdoor:latest
container_name: casdoor
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./conf:/conf
- ./logs:/logs
environment:
RUNNING_IN_DOCKER: "true"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8000/api/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
db:
image: postgres:16-alpine
container_name: casdoor-db
restart: unless-stopped
environment:
POSTGRES_USER: casdoor
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: casdoor
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U casdoor -d casdoor"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
volumes:
postgres_data:Starte den Stack:
cd /opt/casdoor
docker compose up -dBeobachte den Startvorgang. Casdoor benötigt nach dem ersten Start etwas Zeit für die Datenbankinitialisierung. Öffne den Browser erst, wenn du in den Logs „HTTP server Started" siehst:
docker compose logs -f casdoor
# Warte auf:
# ... HTTP server StartedVerifizieren:
docker compose ps
# Erwartete Ausgabe (beide Container im Status "running" / "healthy"):
# NAME IMAGE STATUS
# casdoor casbin/casdoor:latest Up X minutes (healthy)
# casdoor-db postgres:16-alpine Up X minutes (healthy)
# API-Healthcheck per curl:
curl -s http://localhost:8000/api/health
# Erwartete Ausgabe: {"status":"ok"} oder HTTP 200Schritt 5: Erst-Einrichtung in der WebUI
Öffne http://localhost:8000 im Browser. Du gelangst zur Casdoor-Anmeldeseite. Die Standard-Zugangsdaten lauten:
- Organisation:
built-in - Benutzername:
admin - Passwort:
123
Ändere das Admin-Passwort sofort nach dem ersten Login. Das Passwort 123 ist öffentlich bekannt – ist Port 8000 erreichbar, ist deine Instanz sonst unmittelbar kompromittierbar. Klicke oben rechts auf den Benutzernamen → Edit → neues sicheres Passwort setzen und speichern.
In der WebUI kannst du ohne Konfigurationsdateien:
- Organisationen anlegen und Benutzer verwalten (Einzel- oder Bulk-Import)
- Anwendungen registrieren und Client-ID / Client-Secret erzeugen
- Identity Provider einbinden (Google, GitHub, Azure AD, LDAP, SAML-IdP u. v. m.)
- MFA erzwingen – pro Organisation, Anwendung oder Benutzer
- RBAC/ABAC-Richtlinien über die integrierte Casbin-Engine definieren
Um eine Anwendung (z. B. Gitea oder Nextcloud) anzubinden: Applications → Add → Name, Redirect-URI und gewünschte Protokolle (OIDC/OAuth2) eintragen. Casdoor zeigt danach Client-ID und Client-Secret an, die du in der Ziel-App als OAuth2/OIDC-Provider einträgst. Die Standard-Endpunkte sind:
- Authorization:
http://casdoor:8000/login/oauth/authorize - Token:
http://casdoor:8000/api/login/oauth/access_token - UserInfo:
http://casdoor:8000/api/userinfo
Verifizieren: Melde dich mit dem neuen Admin-Passwort ab und wieder an. Der Login muss mit den neuen Zugangsdaten funktionieren. Unter Dashboard sollte die Übersicht mit Organisationen, Benutzern und Anwendungen erscheinen.
Schritt 6: HTTPS mit Reverse Proxy (Produktion)
Casdoor kann TLS nicht selbst terminieren. Für den Produktivbetrieb – und besonders, wenn Casdoor öffentlich erreichbar sein soll – schalte einen Reverse Proxy vor. Eine schnelle Lösung bietet Caddy mit automatischem HTTPS (Let's Encrypt). Die vollständige Einrichtung beschreibt Caddy als Reverse Proxy einrichten.
Passe nach der Proxy-Einrichtung den origin-Parameter in conf/app.conf auf deine öffentliche HTTPS-URL an:
origin = https://auth.example.comDanach Stack neu starten:
cd /opt/casdoor
docker compose restart casdoorVerifizieren:
# HTTPS-Antwort des Reverse Proxys prüfen:
curl -I https://auth.example.com
# Erwartete Ausgabe: HTTP/2 200 (oder 302 zum Login)Schritt 7: Updates und Backup
Casdoor veröffentlicht mehrmals wöchentlich neue Versionen. Für den Produktivbetrieb empfiehlt sich das Pinning auf eine spezifische Version (z. B. casbin/casdoor:3.86.0) statt :latest, um unkontrollierte Updates zu verhindern. Zum Aktualisieren:
cd /opt/casdoor
docker compose pull
docker compose up -dFür das Backup sind zwei Komponenten relevant:
- PostgreSQL-Datenbank: Enthält alle Benutzer, Anwendungen, Richtlinien und JWT-Secrets. Sichere sie regelmäßig mit
pg_dump– wie das geht, erklärt PostgreSQL Backup automatisieren mit cron. - conf/app.conf: Die Konfigurationsdatei enthält den Datenbankverbindungsstring – ebenfalls sichern.
Für die pg_dump-Sicherung direkt aus dem laufenden Container:
docker exec casdoor-db pg_dump -U casdoor casdoor \
| gzip > /opt/backups/casdoor_$(date +%Y%m%d).sql.gzVerifizieren:
docker compose ps
# Beide Container müssen nach dem Update "healthy" sein:
# casdoor casbin/casdoor:3.86.0 Up X minutes (healthy)
# casdoor-db postgres:16-alpine Up X minutes (healthy)
# Backup-Datei vorhanden und nicht leer:
ls -lh /opt/backups/casdoor_*.sql.gzTroubleshooting / Typische Fehler
- „config file not found" beim Start: Das Volume
./conf:/confist gemountet, aberconf/app.conffehlt. Lösung: Datei mitcurlaus dem GitHub-Repo herunterladen (siehe Schritt 2). - „dial tcp 127.0.0.1:5432: connect: connection refused": Die Umgebungsvariable
RUNNING_IN_DOCKER: "true"fehlt incompose.yamlund inapp.confstehtlocalhostals DB-Host. Lösung: Variable setzen oder inapp.confden Service-Namendbals Host verwenden. - „invalid DSN" bei PostgreSQL: Das MySQL-DSN-Format (
root:pass@tcp(host:3306)/) funktioniert nicht für PostgreSQL. Korrektes Format:user=casdoor password=SECRET host=db port=5432 sslmode=disable dbname=casdoor. - „502 Bad Gateway" im Browser: Browser zu früh geöffnet, Casdoor noch beim Initialisieren. Lösung:
docker compose logs -f casdoorbeobachten und warten bis „HTTP server Started" erscheint. - „Permission denied" beim Schreiben in
./logs: Casdoor läuft als UID 1000, der Ordner gehört root. Lösung:chown -R 1000:1000 conf/ logs/auf dem Host ausführen. - Casdoor startet, Datenbank noch nicht bereit:
depends_onohnecondition: service_healthykonfiguriert. Lösung: Healthcheck beimdb-Service definieren undcondition: service_healthynutzen (wie in dieser Anleitung gezeigt). - LDAP-Port 389 kann nicht gebunden werden: Port 389 ist ein privilegierter Port (<1024) und kann von einem nicht-root-Prozess nicht geöffnet werden. Lösung: In
app.confeinen höheren Port konfigurieren, z. B.ldapServerPort = 1389, und incompose.yamlentsprechend mappen. - Interner Port stimmt nicht mit compose.yaml überein: Wenn
httpport = 9000inapp.confsteht, aberports: "8000:8000"incompose.yaml, ist der Dienst intern nicht erreichbar. Lösung: Beide Werte müssen übereinstimmen.
Häufige Fragen
Welche Datenbank soll ich verwenden?
PostgreSQL 16 ist die empfohlene Wahl für den Produktivbetrieb: beste Treiberunterstützung, stabil, ACID-konform. MySQL 8.0+ funktioniert ebenfalls gut. SQLite ist ausschließlich für Entwicklung und Tests geeignet – verwende dafür das Image casbin/casdoor-all-in-one, das SQLite eingebettet hat, aber keinen Datenschutz bei Neustart bietet. CockroachDB, SQL Server, Oracle und TiDB werden unterstützt, sind aber Sonder-Use-Cases.
Wie integriere ich Nextcloud oder Gitea als SSO-Client?
Lege in Casdoor unter Applications → Add eine neue Anwendung an. Trage die Redirect-URI der Ziel-App ein und wähle OIDC als Protokoll. Casdoor generiert Client-ID und Client-Secret. In Nextcloud oder Gitea konfigurierst du dann den OIDC-Provider mit den Endpunkten: Authorization http://casdoor:8000/login/oauth/authorize, Token http://casdoor:8000/api/login/oauth/access_token, UserInfo http://casdoor:8000/api/userinfo.
Wie aktiviere ich MFA für alle Benutzer?
In der WebUI unter Organizations → [Organisation] → Edit kannst du MFA für die gesamte Organisation erzwingen. Unterstützte Methoden: TOTP (Google Authenticator, Authy), SMS-OTP, E-Mail-OTP und Hardware-Security-Keys via WebAuthn/FIDO2. MFA lässt sich auch gezielt pro Anwendung oder pro Benutzer aktivieren.
Wie aktiviere ich HTTPS?
Casdoor selbst terminiert kein TLS. Empfohlen wird ein Reverse Proxy (Caddy, Traefik oder Nginx) vor Casdoor, der HTTPS auf Port 443 terminiert und zu casdoor:8000 weiterleitet. Setze danach in app.conf den Parameter origin = https://auth.example.com und starte den Container neu. Für automatisches HTTPS mit Let's Encrypt bietet sich Caddy als Reverse Proxy an.
Sollte ich :latest oder eine feste Version verwenden?
Casdoor veröffentlicht mehrmals wöchentlich neue Releases (v3.84, v3.85, v3.86 innerhalb weniger Tage). Das ist ein Zeichen aktiver Entwicklung, aber :latest bedeutet, dass docker compose pull jederzeit eine neue Version zieht. Für Produktion empfiehlt sich das Pinning auf eine spezifische, getestete Version: casbin/casdoor:3.86.0. Automatische Update-Überwachung kannst du mit Tools wie Diun oder WUD realisieren, die im Artikel Docker-Container automatisch aktualisieren verglichen werden.
Kann Casdoor selbst als LDAP-Server agieren?
Ja – das ist eine besonders nützliche Funktion für Legacy-Anwendungen, die nur LDAP sprechen. In app.conf aktivierst du den LDAP-Server mit ldapServerPort = 1389 (empfohlen, da Port 389 Privilegien erfordert) und mappst den Port in compose.yaml. Casdoor exponiert dann Benutzer und Gruppen über LDAP – mit demselben zentralen Benutzerstamm, den du in der WebUI verwaltest.
Was ist SCIM 2.0 und wofür brauche ich es?
SCIM 2.0 (System for Cross-domain Identity Management) ermöglicht die automatische Synchronisation von Benutzern und Gruppen zwischen Casdoor und externen Verzeichnisdiensten wie Azure AD oder Okta. Neue Benutzer in Azure AD werden automatisch in Casdoor angelegt, gelöschte Konten werden deaktiviert – ohne manuellen Import.
Fazit
Casdoor ist eine ungewöhnlich vollständige Lösung für einen so kompakten Container: ~54 MB Image-Größe, nativ auf amd64 und arm64 lauffähig, mit einer WebUI, die keine Admin-Konfigurationsdateien für den laufenden Betrieb erfordert. Die Kombination aus OAuth 2.0, OIDC, SAML, LDAP-Server, RADIUS, WebAuthn und einer eingebauten Casbin-Autorisierungsengine macht Casdoor zur universellsten SSO-Lösung für heterogene Self-Hosted-Umgebungen. Der entscheidende Unterschied zu Alternativen wie Authentik oder Keycloak: Casdoor ist deutlich ressourcenschonender und einfacher zu betreiben, verzichtet aber auf Enterprise-Funktionen wie Realm-Isolation oder UI-Theming. Für KMU-Admins und ambitionierte Selfhoster, die eine zentrale Identitätsquelle für Docker-basierte Dienste suchen, ist Casdoor eine ernsthafte Option – vorausgesetzt, man ändert das Standard-Passwort sofort nach dem ersten Start.
Als nächste Schritte empfehlen sich das Absichern des Docker-Stacks nach Best Practices (Non-Root, Healthchecks, Secrets) aus Docker Compose absichern sowie ein Blick auf den Vergleich der SSO-Alternativen in Single Sign-On: Authentik vs. Authelia.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren (Ubuntu/Debian): die Self-Hosting-Grundlage
- Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only für den Produktivbetrieb
- Single Sign-On für den Self-Hosted-Stack: Authentik vs. Authelia mit Traefik Forward-Auth absichern
- MySQL & PostgreSQL Backup automatisieren mit cron
- Docker-Container automatisch aktualisieren nach dem Watchtower-Aus: Diun, WUD und Renovate im Vergleich
- Zitadel mit Docker installieren: Cloud-nativer Identity Server als Keycloak-Alternative
Offizielle Quellen: Casdoor-Dokumentation: Try with Docker | Casdoor GitHub-Repository | casbin/casdoor auf Docker Hub.