Self-hosted service
wheelybird/luminary avatar
wheelybird/luminary

Luminary is an LDAP account management web app that also stores TOTP secrets in the directory

A PHP web-based interface for LDAP user account management and self-service password change.

546 stars120 forksPHPMIT

At a glance

What is it?
Luminary is a PHP web application for managing OpenLDAP user accounts and groups, with self-service password changes and TOTP enrolment backed by LDAP itself, distributed as a Docker image alongside an OpenLDAP container. It suits an administrator who wants a browser interface to a directory, and it expects the directory schema to carry the MFA data, which is a real prerequisite.
Who is it for?
Luminary fits an administrator of an OpenLDAP deployment who wants a browser interface for accounts and groups instead of ldapmodify, and who wants TOTP enrolment to live in the same directory the VPN server reads. It does not fit a directory you cannot extend with a schema, because the MFA features need the TOTP schema, and it does not fit an Active Directory estate, since the project is built around OpenLDAP.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A web front end for the directory, with a rename behind it

Luminary is described as a web-based interface for managing LDAP user accounts and groups, with self-service password management and multi-factor authentication support, and it is written in PHP.

The name is recent. The README opens with a note that the project was previously known as ldap-user-manager, and that anyone looking for that project is in the right place because it is now called Luminary. That detail is worth a moment, because a directory interface is exactly the kind of tool people deploy once and then look for under the old name years later. The old name still works in the container image too: the Dockerfile creates a symlink from /opt/ldap-user-manager to /opt/luminary, so existing deployments that reference the old path keep working.

The scope is LDAP account and group management through a browser: create, edit and delete users, organise users into groups with flexible membership controls, let users change their own passwords, and let users self-enrol a TOTP authenticator with a QR code.

There are also the parts an administrator would otherwise build themselves. A setup wizard that creates the LDAP structure and the first admin account. Optional email delivery of new account credentials. A password generator and strength indicator. A web form through which users request accounts. And branding, since the interface can carry your organisation's logo and styling.

The README frames the relationship with a sibling project precisely: Luminary provides a user-friendly way for administrators to manage accounts and for users to self-enrol in multi-factor authentication, complementing openvpn-server-ldap-otp.

The Docker quick start, which is also the documentation

The quick start is written as a four step test setup, and it doubles as the clearest description of how the pieces fit together.

The first step is an OpenLDAP container with the RFC 2307bis schema enabled and client certificate verification turned off for testing.

bash
docker run \
  --detach \
  --name openldap \
  --hostname openldap \
  -p 389:389 \
  -e LDAP_ORGANISATION="Example Ltd" \
  -e LDAP_DOMAIN="example.com" \
  -e LDAP_ADMIN_PASSWORD="admin_password" \
  -e LDAP_TLS_VERIFY_CLIENT="never" \
  -e LDAP_RFC2307BIS_SCHEMA="true" \
  osixia/openldap:latest

The second step starts Luminary itself, and the environment variables there are the whole configuration surface.

bash
docker run \
  --detach \
  --name luminary \
  -p 8080:80 \
  -p 8443:443 \
  -e SERVER_HOSTNAME="localhost" \
  -e LDAP_URI="ldap://openldap:389" \
  -e LDAP_BASE_DN="dc=example,dc=com" \
  -e LDAP_REQUIRE_STARTTLS="true" \
  -e LDAP_ADMIN_BIND_DN="cn=admin,dc=example,dc=com" \
  -e LDAP_ADMIN_BIND_PWD="admin_password" \
  -e LDAP_IGNORE_CERT_ERRORS="true" \
  --link openldap:openldap \
  wheelybird/luminary:v2.2.1

The third step is the setup wizard at https://localhost:8443/setup, where you accept the self-signed certificate warning and then verify LDAP connectivity, create the organisational units for users and groups, create the admins group, and create your first admin user. The fourth is logging in at the same host with those credentials.

Two details in that command block carry the design. The image tag is pinned to v2.2.1 rather than latest, and both HTTP and HTTPS are published, with HTTPS on 8443 being where the wizard runs.

Configuration is environment variables, and secrets have a file variant

Luminary is configured entirely through environment variables, and only four of them are required.

The essential ones are LDAP_URI for the server URI, LDAP_BASE_DN for the base DN of the organisation, LDAP_ADMIN_BIND_DN for the DN of the admin user, and LDAP_ADMIN_BIND_PWD for that user's password. Everything else has a sensible default, and the example given is the admin group, which defaults to admins and can be changed with LDAP_ADMINS_GROUP.

The documentation is split into three files under docs/. The configuration reference holds the complete list of environment variables with descriptions and defaults, docs/mfa.md covers setting up and using MFA and TOTP authentication, and docs/advanced.md covers HTTPS certificates, custom attributes, email setup and more.

The secrets mechanism is the part with a real design decision in it. For sensitive values you can use Docker secrets or mounted files by appending `_FILE` to any variable name and pointing it at a file containing the value.

bash
-e LDAP_ADMIN_BIND_PWD_FILE=/run/secrets/ldap_admin_password

That is the standard twelve-factor pattern and it applies to any variable, not just the admin password. It matters here because the admin bind credential is the one that lets the application write to the whole directory.

Two other settings in the quick start deserve attention. LDAP_REQUIRE_STARTTLS is set to true in the example, which means the connection is upgraded inside the protocol rather than being plain LDAP over the wire. LDAP_IGNORE_CERT_ERRORS is also set, and that is exactly the setting you would want turned off in production, since it disables verification of the server certificate.

MFA means extending the directory schema first

This is the part of the project that is easiest to miss, and it changes how you plan a deployment.

Luminary supports LDAP-backed TOTP, where the time-based one-time password secrets are stored in the directory rather than in a separate database. Users self-enrol using QR codes with their authenticator apps, administrators can enforce MFA for specific groups, grace periods allow time for users to set up, and backup codes exist for account recovery.

The prerequisite is a schema change. The README notes that if you want to enable MFA support you should follow the quick set-up guide for ldap-totp-schema, which provides instructions for running the osixia/openldap container with support for the TOTP schema, the one that stores MFA information in LDAP. The related projects list names ldap-totp-schema as the LDAP schema for storing TOTP configuration.

So MFA in Luminary is not a toggle inside the application. It requires a directory that understands the TOTP attributes, which for a stock osixia/openldap container means an extra schema file and a restart.

The reason the project stores TOTP secrets in LDAP is visible in the OpenVPN integration section, which describes a five step flow. You use Luminary to create and manage user accounts, users enrol in MFA through the web interface, TOTP secrets are stored in LDAP, the OpenVPN server reads the same LDAP directory for authentication, and users then connect to the VPN with a password plus a TOTP code.

That shared-directory design is the whole point of the pairing, and it is also the thing that makes the schema requirement unavoidable.

The container image and what the Dockerfile reveals

The Dockerfile is short enough to read as a description of the runtime, and it explains several design decisions.

The base is php:8.4-apache, so this is a PHP application served by Apache with mod_rewrite and mod_ssl enabled, and the default site and the default SSL site are disabled so the project can define its own. The entrypoint script is copied to /usr/local/bin/entrypoint and made executable, and the container's command is apache2-foreground.

The application code is copied to /opt/luminary, with the symlink to /opt/ldap-user-manager as noted earlier. The Dockerfile also creates an empty /etc/ldap/ldap.conf, which is the placeholder the OpenLDAP client libraries look for.

The extension builds are explicit. The gd extension is configured with freetype and jpeg support and installed, which is what backs the QR code generation for TOTP enrolment and the avatar or image handling. The ldap extension is configured with a libdir computed at build time by finding libldap.so on the system, because the Debian PHP image does not know where the library lives by default. The build installs libldb-dev, libldap2-dev, libldap-common, libfreetype6-dev, libjpeg-dev, libpng-dev and cron.

One step is about reducing the image rather than adding to it. After installing, the Dockerfile upgrades packages to pick up security patches, marks the runtime libraries as manual so that auto-remove does not delete them, and then purges the development packages including the -dev headers, leaving a smaller image.

PHPMailer is fetched from a pinned GitHub archive at version 7.0.0 and extracted to /opt/PHPMailer, which is what the optional email notifications for new account credentials rely on.

Where Luminary is the wrong choice

Four cases argue against it.

The first is a directory you cannot extend. Every MFA feature depends on the TOTP schema being present in the directory, and if your LDAP server is managed by someone else, or is Active Directory, or is a hosted directory with a fixed schema, that is a blocker rather than a task. The project is built around OpenLDAP and says so.

The second is a large directory at scale. This is a PHP web application that binds as an admin and writes to the directory for every administrative action. The README does not describe pagination, indexes, connection pooling or any behaviour under a directory with hundreds of thousands of entries, and for a directory of that size you would be running an LDAP proxy or a provisioning service instead.

The third is a compliance-driven identity stack. The interface is a browser application with a setup wizard, an email option for credential delivery and an account request form. That is a small internal directory, an organisation's own LDAP for a VPN or mail server, not a workforce identity platform with approval workflows and audit trails.

The alternative in the same direction is to not run an interface at all and script the directory. ldapmodify and ldapsearch do everything Luminary does, and for a small directory with a handful of changes a script is less to deploy and less to secure. The difference in approach is that Luminary gives you a browser for self-service: password changes and TOTP enrolment done by the user, which is the part a directory administrator cannot practically do by hand across many accounts, and which is why openvpn-server-ldap-otp pairs with it.

Editorial conclusion

Luminary fits an administrator of an OpenLDAP deployment who wants a browser interface for accounts and groups instead of ldapmodify, and who wants TOTP enrolment to live in the same directory the VPN server reads. It does not fit a directory you cannot extend with a schema, because the MFA features need the TOTP schema, and it does not fit an Active Directory estate, since the project is built around OpenLDAP. Try it against a throwaway `osixia/openldap` container first, walk the setup wizard at `/setup`, and enable `LDAP_REQUIRE_STARTTLS` before you point it at a real directory.

Frequently asked questions

What is Luminary?

Luminary is a PHP web application for managing LDAP user accounts and groups, with self-service password management and multi-factor authentication support. It was previously known as ldap-user-manager, and the container image keeps a symlink from the old path for existing deployments.

How do I install Luminary?

As a Docker container. The README shows running an osixia/openldap container first, then Luminary with LDAP_URI, LDAP_BASE_DN, LDAP_ADMIN_BIND_DN and LDAP_ADMIN_BIND_PWD set, then visiting /setup to run the wizard. To build from source, clone the repository and run `docker build -t luminary .`.

How does Luminary store TOTP secrets for MFA?

In LDAP itself, using a TOTP schema that has to be added to the directory first. The README points at the ldap-totp-schema project for running osixia/openldap with the TOTP schema, which is what stores the MFA information in LDAP.

How do I pass a password to Luminary without putting it in the environment?

Append `_FILE` to any variable name and point it at a file holding the value, for example `-e LDAP_ADMIN_BIND_PWD_FILE=/run/secrets/ldap_admin_password`. This works with Docker secrets or any mounted file, for any setting rather than only the admin password.

What licence is Luminary released under?

The MIT Licence, with the details in the LICENCE file as the README refers to it. The recent releases are v2.2.1 from 2026-08-04, v2.2.0 from 2026-07-17 and v2.1.1 from 2025-12-12.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. wheelybird/luminary on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wheelybird-luminary.svg)](https://hysenlabs.com/projects/wheelybird-luminary)

Was this useful?