Tech Digest

Identity

LLDAP

A tiny LDAP server for the apps that only speak LDAP

IdentityGPL-3.0Stablearm64 builds
Last reviewed Profile maintained against the project's own documentation
Operational load
1 / 5
Set and forget
Idle memory
15 MB
typical use ~30 MB
Moving parts
1
containers in a normal deployment
Backup shape
SQLite backup
needs a dump or a stop

LLDAP is a small user directory that speaks just enough LDAP for common self-hosted software, with a web UI for managing users and groups. It replaces OpenLDAP or Active Directory in setups that need authentication rather than a directory service.

Our verdict on LLDAP#

Treat LLDAP as a component, not a product. It exists so there is one place to change a password, and it pairs with something else that does the actual single sign-on: Authelia and authentik both take it as an LDAP backend, Keycloak federates users from it, and Pocket ID can sync from it. Used on its own it gives you shared credentials, not shared sessions, and every app still shows its own login form. Be equally clear about what it is not. The README states the goal is not a full LDAP server: generic LDAP browsing tools mostly fail against it, and it will never hand out password hashes, which is why Synology is named as incompatible. The release cadence is slow and unapologetic about it, 0.6.2 in August 2025 and 0.6.3 in April 2026, still pre-1.0 after five years. It is around 15 MB of Rust and it does not fall over.

Who LLDAP is for#

Choose it if

  • Jellyfin, Nextcloud, Forgejo and Grafana all keeping their own user tables, and you want one password across the set.
  • Deploying Authelia or authentik and wanting a real directory behind it instead of a YAML file of hashes.
  • Low-power hosts, where a Rust binary and a SQLite file is the entire footprint you can spare.
  • Anyone who has configured OpenLDAP once and does not intend to repeat the experience.

Look elsewhere if

  • You need an actual directory service: schema extensions, referrals, replication, Kerberos, or anything that browses the tree.
  • Your app validates passwords by fetching the hash and comparing it itself. LLDAP will not expose hashes, and Synology is the documented casualty.
  • You expected single sign-on. There is no OIDC, no SAML and no session concept; LLDAP needs a partner to deliver that.

What running it actually looks like#

One container. Mount /data, set LLDAP_JWT_SECRET, LLDAP_KEY_SEED and LLDAP_LDAP_USER_PASS, and choose your base DN (dc=example,dc=com by default) up front, because changing it later means rewriting the bind configuration in every client. It listens on 3890 for LDAP, 6360 for LDAPS if you enable it, and 17170 for the web UI. The tree is fixed and shallow: users at cn=<user>,ou=people,<base>, groups at cn=<group>,ou=groups,<base>, admin at cn=admin,ou=people,<base>. Most clients want a service account for the bind, so create a dedicated user in lldap_strict_readonly rather than handing the admin password to six different applications. A rootless image variant exists. Upgrades are a tag bump with automatic migrations; the bootstrap.sh script lets you define users and groups declaratively instead of clicking.

Resource profile#

Memory
15 MB idle, around 30 MB in ordinary use. A single Rust binary plus a Rust and WebAssembly admin UI, with SQLite in-process. Estimated from typical installs; the project describes it as low resource but publishes no number.
CPU and acceleration
Effectively nothing at rest. Password verification is the only cost and it is deliberately expensive per attempt, so a service that binds on every single request rather than caching will show up in your CPU graph.
Storage growth
Kilobytes per user. The database holds accounts, groups, custom attributes and hashed credentials, and it does not grow on its own. Avatars are the only variable-size content.
Operational load
1 of 5, Set and forget. One container, one SQLite file, automatic migrations, and backup that is a file copy of a stopped instance. Releases are roughly annual, so the attention it costs is mostly reading a changelog when you finally do upgrade.

Figures describe a small single-household install and are the working assumptions behind our stack planner. Your numbers will differ with library size, user count and hardware. See methodology.

Data and backup surface#

/data and nothing else: users.db if you are on SQLite, plus private_key when you let it generate one instead of supplying LLDAP_KEY_SEED. That key is what makes stored passwords usable, so a database backup without it is worthless. If you set a key seed, that string is part of the backup and belongs in a password manager rather than in the same tarball. Changing jwt_secret invalidates every session and forces everyone to log in again, which is a useful emergency lever and a bad accident. Stop the container or use the sqlite3 .backup command rather than copying users.db live. On PostgreSQL it is pg_dump plus the key seed.

Derived backup shape

SQLite backup. sqlite3 <db> ".backup out.db" while running, or stop the container and copy. A live cp of a WAL-mode SQLite file can restore corrupt.

Traps and surprises#

The key seed is half of your backup

The private key, generated on first run or derived from LLDAP_KEY_SEED, is what makes the stored passwords usable. Restore users.db onto an instance with a different seed and nobody can authenticate, including the admin. The only way out is force_ldap_user_pass_reset to recover the admin account and a manual password reset for every other user. Store the seed alongside the backup, not inside it.

Not a real LDAP server, on purpose

The README says outright that the goal is not to provide a full LDAP server. Apache Directory Studio and similar browsers largely do not work against it, and any service that expects to fetch a password hash and compare it locally will never work at all. Synology is the documented example. Check the example_configs directory for your application before you commit to LLDAP as your directory.

The 0.5.0 uniqueness migration can block you

0.5.0 made emails and UUIDs unique, and the change closed an account takeover path, so it is not optional. If your directory has two users sharing an email address the migration will not complete: you have to disambiguate them with SQL against the database first, or roll back to the earlier version, fix the data, and upgrade again. Check for duplicates before you pull a newer tag.

The group rename in 0.4.0

lldap_readonly was renamed to lldap_password_manager in 0.4.0, and a genuinely read-only lldap_strict_readonly group was introduced alongside it. Service accounts created before that release ended up in a group that can change other people's passwords. If you set up a bind account years ago and never revisited it, check which group it is in and move it to lldap_strict_readonly.

memberOf only got proper schema in 0.6.3

0.6.3 (April 2026) added LDAP schema definitions for memberOf, modifyTimestamp and pwdChangedTime. Clients that validate the schema before filtering on group membership, rather than just reading the attribute, failed against earlier releases in ways that looked like a group mapping bug. If group-based access control is not matching in a picky client, confirm you are on 0.6.3 or later before debugging anything else.

Specifications#

Category
Passwords, SSO and identity
Licence
GPL-3.0 (Copyleft)
Written in
Rust
First release
2021
Maturity
Stable
Datastore
SQLite (default), PostgreSQL or MySQL/MariaDB
Default ports
3890, 6360, 17170
Ships as
docker, native binary, nixos module
arm64 builds
Yes
Identity
LDAP only. It is the LDAP server and nothing else. No OIDC in either direction, so by itself it gives you one password everywhere, not one session.
Replaces
Microsoft Active Directory, JumpCloud, Okta Universal Directory
Project site
github.com/lldap/lldap
Source
github.com/lldap/lldap
Documentation
github.com/lldap/lldap/blob/main/README.md

Alternatives to LLDAP#

Everything else in passwords, sso and identity, closest in operational weight first.

ToolOps loadIdle RAMLicence
Pocket ID1, Set and forget30 MBBSD-2-Clause
Vaultwarden2, Light40 MBAGPL-3.0
Authelia3, Moderate35 MBApache-2.0
Keycloak4, Heavy750 MBApache-2.0
authentik4, Heavy1000 MBMIT (core); authentik/enterprise/ under a separate Authentik Security license

Where LLDAP comes up elsewhere#

Sources#

Facts on this page were checked against the project's own material. Where a number is our own estimate rather than a published figure, the text says so.

  1. Project README, scope and limitations
  2. Docker configuration template with default ports
  3. Changelog and breaking changes
  4. Releases
  5. Tags and release history

Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.