Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 29.09.2026 · 15 min Lesezeit

lldap mit Docker Compose: zentrales Benutzerverzeichnis für Selfhosting-Dienste

lldap ist ein leichtgewichtiger LDAP-Server mit Weboberfläche, der Benutzer und Gruppen zentral für Selfhosting-Dienste bereitstellt. Die Anleitung zeigt compose.yaml, Benutzer per API, Leserechte-Konto, Test mit ldapsearch, Backup mit Restore-Beweis und warum ohne den Schlüssel-Seed nach dem Restore nichts mehr startet.

Mit KI erstellt – redaktionelle Prüfung ausstehend

Hero-Grafik zur Anleitung lldap mit Docker: zentrale Benutzerverwaltung mit Karten für Benutzer und Gruppen, LDAP-Anmeldung sowie Backup und Restore

Sobald im Firmennetz mehr als drei selbst gehostete Dienste laufen, beginnt das Kontenchaos: Gitea, Nextcloud, Wiki, Monitoring und Passwortmanager führen jeweils eigene Benutzerlisten, und beim Ausscheiden einer Mitarbeiterin muss jemand an fünf Stellen daran denken, das Konto zu sperren. Ein zentrales Verzeichnis per LDAP löst genau das. Klassische Server wie OpenLDAP sind dafür aber für kleine Umgebungen schwer zu bedienen.

lldap (Light LDAP) setzt hier an: ein schlanker LDAP-Server mit Weboberfläche, der nur das kann, was Anwendungen für die Anmeldung wirklich brauchen, nämlich Benutzer, Gruppen, Passwörter und Gruppenmitgliedschaften. Diese Anleitung zeigt den Betrieb per Docker Compose von der compose.yaml über das Anlegen von Benutzern per API bis zu Backup, Restore und sauberer Deinstallation. Alle Kernschritte wurden am 29.09.2026 auf einem Linux-Host mit Docker praktisch durchgespielt, inklusive eines wichtigen Fundes: Wer beim Restore den falschen Schlüssel-Seed verwendet, bekommt einen Server, der gar nicht mehr startet.

Was lldap ist und wo die Grenzen liegen

lldap ist ein in Rust geschriebener, bewusst vereinfachter LDAP-Server unter GPL-3.0. Das Projekt hatte laut GitHub-API am 29.09.2026 rund 6.532 Sterne, der letzte Push war am 26.09.2026, das Repository ist nicht archiviert. Das neueste Release ist v0.6.3 vom 30.04.2026. Neben LDAP auf Port 3890 bringt lldap eine Weboberfläche und eine GraphQL-API auf Port 17170 mit.

Wofür lldap gut ist:

  • Zentrale Anmeldung für Dienste mit LDAP-Unterstützung wie Gitea, Forgejo, Nextcloud, Jellyfin, Grafana oder Vaultwarden. Das Projekt pflegt dafür rund 90 Beispielkonfigurationen im Ordner example_configs.
  • Benutzerquelle für einen Identity Provider wie Authelia, Authentik, Keycloak oder Pocket ID, die dann SSO per OIDC oder Forward-Auth übernehmen.
  • Gruppenbasierte Zugriffssteuerung über memberOf-Filter, zum Beispiel nur Mitglieder von git_user dürfen sich an Gitea anmelden.
  • Selbstverwaltung: Benutzer können ihr Passwort in der Weboberfläche ändern, mit SMTP auch per Link zurücksetzen.

Die Grenzen sind gewollt und stehen so auch in der Projektdokumentation:

  • Kein vollständiger LDAP-Server: Schemaänderungen per LDAP, Replikation und die meisten Schreiboperationen über LDAP werden nicht unterstützt. Über LDAP funktionieren laut Doku nur Lesezugriffe, das Anlegen von Benutzern und Passwortänderungen.
  • Kein anonymer Bind. Jeder Dienst braucht ein eigenes Bind-Konto.
  • Kein Ersatz für Active Directory: keine Gruppenrichtlinien, kein Kerberos, keine Windows-Domäne. Linux-Anmeldung über PAM und nslcd ist dokumentiert, Samba-Integration laut README noch in Arbeit.
  • Kein SSO im engeren Sinn. lldap prüft Passwörter, die Sitzung über mehrere Dienste hinweg liefert erst ein vorgeschalteter Identity Provider.

Voraussetzungen und Ressourcen

  • Linux-Host mit Docker Engine und Compose-Plugin (im Test Docker 29 mit Compose v2).
  • Sehr wenig RAM: Der Container belegte nach dem Start im Test 8,1 MiB. Das Image lldap/lldap:v0.6.3 ist rund 28 MB groß.
  • Ein freier Port für die Weboberfläche und, falls Dienste außerhalb von Docker zugreifen, einer für LDAP.
  • Für den Produktivbetrieb ein Reverse Proxy mit TLS vor der Weboberfläche.

Laut Docker Hub gibt es das Image für amd64, arm64 und armv7, damit läuft lldap auch auf einem Raspberry Pi oder einem ARM-NAS. Varianten gibt es auf Alpine- und Debian-Basis sowie als -rootless-Image, das direkt als unprivilegierter Benutzer startet.

Welches Image-Tag: stable, v0.6.3 oder latest?

Die offizielle Doku nutzt lldap/lldap:stable. Am 29.09.2026 zeigte stable auf Docker Hub auf dasselbe Image wie v0.6.3 und v0.6 (alle vom 30.04.2026, identische Größe). Das Tag latest und die datierten Tags wie 2026-09-22 sind dagegen Nightly-Builds aus dem Hauptzweig, die laut Doku instabil sein können. Diese Anleitung pinnt v0.6.3, damit ein Update eine bewusste Entscheidung bleibt. Die getestete Version meldete sich mit lldap 0.6.3.

TagInhaltEmpfehlung
v0.6.3festes ReleaseProduktivbetrieb, reproduzierbar
stablejeweils neuestes Releasewenn automatische Updates gewollt sind
latest, 2026-09-22Nightly aus dem Hauptzweignur zum Testen neuer Funktionen
*-rootlessstartet direkt als Benutzer statt als rootnach Einrichtung der Rechte empfohlen

Vollständige compose.yaml und .env

Die folgende Datei basiert auf dem Beispiel aus docs/install.md, wurde aber auf ein festes Tag, einen Bind-Mount statt eines benannten Volumes und Geheimnisse aus einer .env umgestellt. Genau diese Datei lief im Test, dort nur mit anderen Hostports.

services:
  lldap:
    image: lldap/lldap:v0.6.3
    container_name: lldap
    restart: unless-stopped
    ports:
      # Weboberfläche und GraphQL-API, nur lokal für den Reverse Proxy
      - "127.0.0.1:17170:17170"
      # LDAP, nur lokal; Dienste im selben Docker-Netz brauchen keinen Port
      - "127.0.0.1:3890:3890"
    volumes:
      - "./lldap_data:/data"
    environment:
      - UID=1000
      - GID=1000
      - TZ=Europe/Berlin
      - LLDAP_JWT_SECRET=${LLDAP_JWT_SECRET}
      - LLDAP_KEY_SEED=${LLDAP_KEY_SEED}
      - LLDAP_LDAP_BASE_DN=dc=example,dc=com
      - LLDAP_LDAP_USER_PASS=${LLDAP_LDAP_USER_PASS}

Die .env im selben Verzeichnis erzeugen Sie mit Zufallswerten und schützen sie vor fremdem Lesezugriff:

mkdir -p /opt/lldap/lldap_data
cd /opt/lldap
# Zufällige Geheimnisse erzeugen
printf 'LLDAP_JWT_SECRET=%s\nLLDAP_KEY_SEED=%s\nLLDAP_LDAP_USER_PASS=%s\n' \
  "$(openssl rand -base64 36 | tr -d '/+=')" \
  "$(openssl rand -base64 36 | tr -d '/+=')" \
  "$(openssl rand -base64 24 | tr -d '/+=')" > .env
chmod 600 .env

Beispielinhalt ohne echte Werte:

LLDAP_JWT_SECRET=HIER_ZUFALLSWERT_MIN_32_ZEICHEN
LLDAP_KEY_SEED=HIER_ZUFALLSWERT_MIN_12_ZEICHEN
LLDAP_LDAP_USER_PASS=HIER_START_PASSWORT_ADMIN

Dateipfade und Parameter

Parameter oder PfadBedeutung
/data (Host: ./lldap_data)enthält users.db (SQLite mit allen Benutzern, Gruppen und Passwort-Hashes) und lldap_config.toml, die der Entrypoint beim ersten Start aus einer Vorlage anlegt.
LLDAP_KEY_SEEDSeed für den privaten Serverschlüssel, mit dem die Passwörter gespeichert werden. Muss dauerhaft gleich bleiben, siehe Backup.
LLDAP_JWT_SECRETsigniert die Anmelde-Token der Weboberfläche und API. Ein Wechsel meldet alle Sitzungen ab.
LLDAP_LDAP_BASE_DNWurzel des Verzeichnisses. Benutzer liegen unter ou=people, Gruppen unter ou=groups.
LLDAP_LDAP_USER_PASSPasswort des Kontos admin, gilt nur beim allerersten Start.
UID, GIDBenutzer, unter dem lldap nach dem Start läuft und dem die Dateien in /data gehören. Im Test gehörten beide Dateien danach 1000:1000.
LLDAP_JWT_SECRET_FILE, LLDAP_KEY_SEED_FILEAlternative zu Umgebungsvariablen: Pfad zu einer Datei mit dem Geheimnis, etwa als Docker Secret. Diese Variablen haben Vorrang.

Die Vorlage lldap_config.docker_template.toml dokumentiert alle weiteren Optionen, etwa SMTP für Passwort-Reset, LDAPS mit eigenem Zertifikat oder eine externe Datenbank per LLDAP_DATABASE_URL (MySQL, MariaDB, PostgreSQL). Umgebungsvariablen mit Präfix LLDAP_ überschreiben die Datei, verschachtelte Optionen werden mit doppeltem Unterstrich geschrieben, etwa LLDAP_SMTP_OPTIONS__SERVER.

Installation und Start

cd /opt/lldap
docker compose up -d
# Startmeldungen prüfen
docker compose logs --no-log-prefix | grep -E 'version|Starting|Could not|Successfully'

Im Test erschienen beim ersten Start genau diese Meldungen: das Kopieren der Standardkonfiguration nach /data/lldap_config.toml, Starting LLDAP version 0.6.3, die Datenbank-Migrationen bis Schema-Version 11, das automatische Anlegen der Gruppen lldap_admin, lldap_password_manager und lldap_strict_readonly sowie Successfully (re)set password for "admin". Danach lauschen der LDAP-Server auf 3890 und die Weboberfläche auf 17170. Die Warnung A key_seed was given, we will ignore the key_file ist harmlos und bestätigt nur, dass der Seed aus der .env greift.

Funktionsprüfung und Healthcheck

Das Image bringt einen eigenen Healthcheck mit (/app/lldap healthcheck), eine eigene healthcheck:-Sektion in der Compose-Datei ist nicht nötig. Er prüft LDAP und API und war im Test nach etwa 30 Sekunden healthy.

docker compose ps
# Weboberfläche muss HTTP 200 liefern
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:17170/
# Healthcheck manuell ausführen, Exit-Code 0 erwartet
docker exec lldap /app/lldap healthcheck --config-file /data/lldap_config.toml

Die Ausgabe des Healthchecks endet mit check_ldap ... Success und check_api ... Success, LDAPS wird als LDAPS not enabled übersprungen.

Erstkonfiguration: Benutzer, Gruppen und Bind-Konto

In der Weboberfläche melden Sie sich als admin mit dem Passwort aus der .env an und legen dort Benutzer und Gruppen per Klick an. Für Skripte und wiederholbare Einrichtung eignet sich die GraphQL-API, die im Test so funktioniert hat:

cd /opt/lldap
set -a; . ./.env; set +a
# Anmelde-Token holen
TOKEN=$(curl -s -X POST http://127.0.0.1:17170/auth/simple/login \
  -H 'Content-Type: application/json' \
  -d "{\"username\":\"admin\",\"password\":\"$LLDAP_LDAP_USER_PASS\"}" \
  | python3 -c 'import json,sys;print(json.load(sys.stdin)["token"])')
# Benutzer anlegen
curl -s http://127.0.0.1:17170/api/graphql \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"query":"mutation{createUser(user:{id:\"jdoe\",email:\"jdoe@example.com\",displayName:\"Jana Doe\",firstName:\"Jana\",lastName:\"Doe\"}){id}}"}'
# Gruppe anlegen, die Antwort enthält die numerische Gruppen-ID
curl -s http://127.0.0.1:17170/api/graphql \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"query":"mutation{createGroup(name:\"git_user\"){id}}"}'
# Benutzer der Gruppe mit ID 4 zuordnen
curl -s http://127.0.0.1:17170/api/graphql \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"query":"mutation{addUserToGroup(userId:\"jdoe\",groupId:4){ok}}"}'

Passwörter setzt das mitgelieferte Werkzeug lldap_set_password im Container:

docker exec lldap /app/lldap_set_password \
  --base-url http://localhost:17170 \
  --admin-username admin --admin-password "$LLDAP_LDAP_USER_PASS" \
  --username jdoe --password 'NeuesPasswort!'

Die Antwort lautet Successfully changed jdoe's password. Ist das Admin-Passwort falsch oder leer, bricht das Werkzeug mit 401 Unauthorized ... /auth/simple/login ab, was im Test genau so passierte, als die Variable in der Shell nicht gesetzt war.

Wichtig für jede Anbindung: Dienste sollten sich nicht mit admin verbinden. Legen Sie pro Dienst oder zumindest einmal ein Konto wie bind_user an und nehmen Sie es in die Gruppe lldap_strict_readonly auf. Soll der Dienst Passwörter ändern dürfen, etwa Authelia mit Passwort-Reset, ist stattdessen lldap_password_manager vorgesehen. Im Test durfte bind_user alle Benutzer lesen, ein Versuch, per API einen Benutzer anzulegen, endete dagegen mit Unauthorized user creation.

LDAP-Anmeldung mit ldapsearch testen

Ob die Anbindung funktioniert, prüfen Sie mit ldapsearch aus dem Paket ldap-utils (Debian, Ubuntu) oder openldap-clients (Alpine, RHEL). Ohne Installation auf dem Host reicht ein Wegwerf-Container im Compose-Netz. Der Netzname ist <Verzeichnisname>_default, hier lldap_default:

docker run --rm --network lldap_default alpine:3.20 sh -c \
  "apk add -q openldap-clients && ldapsearch -x -H ldap://lldap:3890 \
  -D 'uid=bind_user,ou=people,dc=example,dc=com' -w 'BindPasswort' \
  -b 'ou=people,dc=example,dc=com' '(uid=jdoe)' uid mail cn memberOf"

Im Test lieferte die Suche den Eintrag dn: uid=jdoe,ou=people,dc=example,dc=com mit cn: Jana Doe, mail und memberOf: cn=git_user,ou=groups,dc=example,dc=com. Auch der Filter (memberOf=cn=git_user,ou=groups,dc=example,dc=com) und die Gegenrichtung über das Attribut member der Gruppe funktionierten. Eine Anmeldung, wie sie ein Dienst prüft, entspricht einem Bind als Benutzer, ldapwhoami antwortete mit Result: Success (0), auch vom Host über den lokal veröffentlichten Port.

Genauso wichtig sind die Gegenproben, alle im Test ausgeführt:

  • Falsches Passwort beim Bind: ldap_bind: Invalid credentials (49).
  • Suche ohne Bind: Inappropriate authentication (48) mit dem Hinweis Anonymous bind not allowed.
  • Falsches Passwort an der Web-Anmeldung: HTTP 401.
  • GraphQL ohne Token: HTTP 401.
  • Normaler Benutzer fragt die Benutzerliste ab: Unauthorized access to user list.

Praxisbeispiel: Gitea, Authelia und weitere Dienste anbinden

Die Beispielkonfigurationen im Repository sind die verlässlichste Vorlage. Für Gitea und Forgejo beschreibt example_configs/gitea.md eine Authentifizierungsquelle vom Typ LDAP (via BindDN) mit diesen Werten:

  • Host: lldap (Dienstname im gemeinsamen Docker-Netz), Port 3890
  • Bind DN: das Leserechte-Konto, etwa uid=bind_user,ou=people,dc=example,dc=com
  • User Search Base: ou=people,dc=example,dc=com
  • User Filter nur für Mitglieder von git_user: (&(memberof=cn=git_user,ou=groups,dc=example,dc=com)(|(uid=%[1]s)(mail=%[1]s)))
  • Admin Filter: (memberof=cn=lldap_admin,ou=groups,dc=example,dc=com), falls lldap-Admins auch Gitea-Admins sein sollen
  • Attribute: uid, givenName, sn, mail, jpegPhoto

Für Authelia gibt es eine eigene Implementierung lldap, die die passenden Standardwerte mitbringt. Die Vorlage aus dem Repository sieht so aus:

authentication_backend:
  refresh_interval: '1m'
  ldap:
    implementation: 'lldap'
    address: 'ldap://lldap:3890'
    base_dn: 'DC=example,DC=com'
    user: 'UID=bind_user,OU=people,DC=example,DC=com'
    password: 'REPLACE_ME'

Nextcloud bindet lldap über die App user_ldap an, das Repository enthält dafür ein vollständiges occ ldap:set-config-Skript mit einer Gruppe nextcloud_users als Zugangsfilter. Pocket ID kann Benutzer und Gruppen aus lldap synchronisieren und ergänzt Passkey-Anmeldung per OIDC. Diese Anbindungen wurden hier nicht mit laufendem Gitea, Authelia oder Nextcloud getestet, geprüft wurden die zugrunde liegenden LDAP-Abfragen und Filter.

Persistente Daten und Rechte

Der Standard-Container startet als root, passt die Rechte in /data an und wechselt dann auf UID und GID. Im Test lagen danach users.db (139.264 Byte) und lldap_config.toml mit Eigentümer 1000:1000 im Bind-Mount. Das README empfiehlt, nach der Einrichtung auf ein -rootless-Image zu wechseln. Dann entfallen UID und GID als Variablen, stattdessen setzen Sie in der Compose-Datei user: "1000:1000", und das Verzeichnis muss vorher diesem Benutzer gehören.

Eine Besonderheit, die im Test bestätigt wurde: Das Admin-Passwort aus der .env gilt nur beim ersten Start. Wer es später in der .env ändert und den Container neu erstellt, kann sich weiter nur mit dem alten Passwort anmelden (neues Passwort HTTP 401, altes HTTP 200). Ändern Sie das Passwort deshalb in der Weboberfläche. Für den Notfall kennt lldap LLDAP_FORCE_LDAP_USER_PASS_RESET=true, das beim nächsten Start das Passwort aus der Konfiguration erzwingt; danach die Variable wieder entfernen.

Netzwerkfreigabe, Reverse Proxy und TLS

Das README empfiehlt eine klare Aufteilung: Die Weboberfläche geht über einen Reverse Proxy mit TLS nach außen, der LDAP-Port wird gar nicht veröffentlicht, weil die anbindenden Dienste im selben Docker-Netz liegen. Praktisch bedeutet das:

  • Port 17170 nur an 127.0.0.1 binden oder ganz weglassen und den Proxy per Docker-Netz auf lldap:17170 zeigen lassen.
  • Port 3890 nur veröffentlichen, wenn Dienste außerhalb von Docker zugreifen, und dann auf die interne Schnittstelle begrenzen. Im Test waren beide Ports laut ss -ltn ausschließlich auf 127.0.0.1 erreichbar.
  • LDAP ohne TLS überträgt Bind-Passwörter im Klartext. Für Verbindungen über das Netz aktivieren Sie LDAPS mit LLDAP_LDAPS_OPTIONS__ENABLED=true, LLDAP_LDAPS_OPTIONS__CERT_FILE und LLDAP_LDAPS_OPTIONS__KEY_FILE auf Port 6360.
  • Den LDAP-Port nie ins Internet freigeben, auch nicht mit LDAPS. Brute-Force auf den Bind ist dort nur eine Frage der Zeit.
  • Bei Betrieb unter einer Subdomain LLDAP_HTTP_URL=https://lldap.example.com setzen, damit Links in Reset-Mails stimmen.

Die Proxy-Konfiguration selbst ist unspektakulär, ein einfacher HTTP-Proxy auf Port 17170 genügt. Wie das mit Traefik aussieht, zeigt die S-EDV-Anleitung zu Forward-Auth mit Authentik und Authelia.

Backup und Restore

Ein brauchbares Backup besteht aus zwei Teilen, die zusammengehören: dem Verzeichnis /data mit users.db und der .env mit LLDAP_KEY_SEED und LLDAP_JWT_SECRET. Bei SQLite ist ein kaltes Backup mit kurz gestopptem Container am einfachsten und im Test in wenigen Sekunden erledigt:

cd /opt/lldap
docker compose stop lldap
tar czf /backup/lldap-$(date +%F).tar.gz lldap_data .env compose.yaml
docker compose start lldap
# Archiv prüfen
tar tzf /backup/lldap-$(date +%F).tar.gz

Der Restore wurde im Test mit einem gelöschten Datensatz bewiesen: Benutzer jdoe per API gelöscht, danach schlug der LDAP-Bind mit Invalid credentials (49) fehl. Dann Container gestoppt, Datenverzeichnis entfernt und aus dem Archiv zurückgespielt. Die Prüfsumme der users.db stimmte mit dem Stand beim Backup überein, nach dem Start fand ldapsearch den Benutzer samt Gruppe git_user wieder, und der Bind mit dem alten Passwort lieferte Success (0).

cd /opt/lldap
docker compose stop lldap
rm -rf lldap_data
tar xzf /backup/lldap-2026-09-29.tar.gz lldap_data .env
docker compose start lldap

Der wichtigste Fund des Tests betrifft den Schlüssel-Seed. Wird die Datenbank mit einem anderen LLDAP_KEY_SEED gestartet, etwa weil die .env verloren ging und neu erzeugt wurde, startet lldap überhaupt nicht mehr. Der Container geht in eine Neustart-Schleife, der Healthcheck meldet unhealthy, und im Log steht:

Error: The private key has changed. ...
The private key encoding the passwords has changed since last successful startup.
Changing the private key will invalidate all existing passwords. If you want to
proceed, restart the server with the CLI arg --force-update-private-key=true or
the env variable LLDAP_FORCE_UPDATE_PRIVATE_KEY=true.

Mit dem ursprünglichen Seed lief derselbe Datenstand sofort wieder, alle Passwörter funktionierten. Der Ausweg LLDAP_FORCE_UPDATE_PRIVATE_KEY=true macht laut Meldung alle vorhandenen Passwörter ungültig. Ohne den Seed ist das Backup also nur noch eine Liste von Benutzern und Gruppen, jedes Konto braucht ein neues Passwort. Sichern Sie die .env deshalb immer mit, aber getrennt geschützt, etwa verschlüsselt oder im Passwortmanager.

Ein Stolperstein beim Testen am Rande: Wer die .env vorher per set -a; . ./.env in die Shell geladen hat, sollte wissen, dass exportierte Shell-Variablen bei Docker Compose Vorrang vor der .env haben. Eine geänderte .env wirkt dann nicht, Compose meldet Starting statt Recreate. Also neue Shell öffnen oder Variablen mit unset entfernen.

Updates und Rollback-Grenzen

Ein Update besteht aus dem Anheben des Tags in der compose.yaml, danach docker compose pull und docker compose up -d. Beim Start migriert lldap das Datenbankschema automatisch, im Test von Version 1 bis 11 in einem Durchlauf. Ein Update-Lauf selbst wurde nicht getestet, weil v0.6.3 am Testtag das neueste Release war.

  • Vor jedem Update ein kaltes Backup wie oben ziehen.
  • Die Release-Notes im GitHub-Repository lesen, vor allem bei Sprüngen über mehrere Minor-Versionen.
  • Ein Rollback auf das alte Image funktioniert nach einer Schemamigration nicht zuverlässig. Sicher ist nur: altes Tag eintragen und das vor dem Update gezogene Backup zurückspielen.
  • Kein automatisches Update per Watchtower auf latest, das sind Nightly-Builds.

Typische Fehler mit Diagnose und Lösung

SymptomUrsacheLösung
Container startet ständig neu, Log: The private key has changedanderer LLDAP_KEY_SEED als beim letzten Startursprünglichen Seed aus dem Backup der .env wiederherstellen
Admin-Login schlägt nach Änderung in der .env fehlPasswort aus der Konfiguration gilt nur beim Erststartaltes Passwort nutzen oder einmalig LLDAP_FORCE_LDAP_USER_PASS_RESET=true
Inappropriate authentication (48), Anonymous bind not allowedDienst versucht anonymen BindBind DN und Passwort eines Leserechte-Kontos eintragen
Invalid credentials (49)falsches Passwort, falscher Bind DN oder Benutzer existiert nichtDN-Schema uid=NAME,ou=people,dc=... und Base DN prüfen
Can't contact LDAP server (-1)lldap läuft nicht oder Dienst ist nicht im selben Docker-Netzdocker compose ps, Netz des Dienstes prüfen, Log lesen
lldap_set_password meldet 401 Unauthorizedfalsches oder leeres Admin-PasswortVariable in der Shell prüfen, Passwort in Anführungszeichen
Dienst zeigt keine Gruppenfalscher Gruppenfilter oder falsches MitgliedsattributGruppen liegen unter ou=groups, Mitglieder im Attribut member, Benutzer tragen memberOf
Keine users.db in /dataVerzeichnis für den Container-Benutzer nicht beschreibbarEigentümer auf UID:GID setzen, laut FAQ notfalls Schreibrechte erweitern

Für tiefere Diagnose lässt sich in der lldap_config.toml verbose = true setzen. Das Log zeigt dann jede LDAP-Anfrage samt angefragter Attribute, was bei Diensten mit eigenwilligen Filtern hilft.

Saubere Deinstallation

Achtung, Datenverlust: Die folgenden Befehle löschen alle Benutzer, Gruppen und Passwort-Hashes unwiderruflich. Alle angebundenen Dienste verlieren damit ihre Anmeldequelle. Ziehen Sie vorher ein Backup, wenn auch nur die Möglichkeit besteht, dass Sie die Daten noch brauchen.

cd /opt/lldap
docker compose down -v --remove-orphans
docker rmi lldap/lldap:v0.6.3
# Daten und Geheimnisse entfernen
rm -rf /opt/lldap

Gehören Dateien in lldap_data einem anderen Benutzer als Ihrem, schlägt rm ohne Root-Rechte fehl. Dann mit sudo löschen. Prüfen Sie abschließend mit docker ps -a --filter name=lldap, dass kein Container übrig ist.

Testumfang

Getestet wurden am 29.09.2026 mit lldap v0.6.3 Start, Healthcheck, Anlegen von Benutzern, Gruppen und Bind-Konto per GraphQL-API und lldap_set_password, LDAP-Suche und Bind mit Positiv- und Negativfällen, das Verhalten des Admin-Passworts, kaltes Backup und Restore mit zuvor gelöschtem Benutzer sowie der Start mit falschem Schlüssel-Seed. Nur aus der Dokumentation stammen die Anbindung von Gitea, Authelia, Nextcloud und Pocket ID, LDAPS, SMTP, Reverse Proxy, Rootless-Betrieb und Updates auf spätere Versionen.

Passende Anleitungen auf S-EDV

Quellen

lldapLDAPDocker ComposeBenutzerverwaltungSelfhostingAutheliaGiteaBackup