· openldap

The Flat File Is a Feature

The docs call slapd.conf deprecated. My clients like it anyway. Here's why that's not nostalgia but a deliberate engineering choice.

OpenLDAP’s own Administrator’s Guide, in the chapter on configuring slapd, says the flat file is on its way out: “The older style slapd.conf(5) file is still supported, but its use is deprecated and support for it will be withdrawn in a future OpenLDAP release.” The replacement is cn=config, the runtime-editable configuration tree introduced back in the 2.3 days.

I read that note every couple of years. I still draw my clients a flat file.

⚙️ What cn=config actually is

The dynamic backend has one advantage: changes can be made without restarting slapd. Run ldapmodify and the new overlay, index, or log level takes effect on the running server with no restart. For a directory that serves 20K RFC2307 lookups per second, never taking it down to reconfigure sounds like an indisputable win.

The same property that makes it powerful is the one that can cause a lot of problems.

⚠️ The feature that is also the sharp edge

A runtime-editable configuration means every configuration change is a live change to the directory of record. There is no staging step in the mechanism, and no restart acting as a checkpoint. The moment your ldapmodify returns, the new ACL is already deciding who can read what, in production, for everyone.

Most of the time that is fine. The problem is the day you discover that a sensitive attribute type is exposed to the wrong user. An untested access rule doesn’t wait politely for a maintenance window to reveal itself; it is already the policy.

Restarting a server in a replicated environment costs almost nothing. The LDAP client by default will fail over to the next server in the list, or hit the load balancer URI again, opening up a connection to another server.

With a flat file, the change goes through source control and review before it ever reaches a server: you edit the file, you diff it against what is running, and you restart slapd on your schedule, in a rolling fashion, across your replica set. That restart isn’t overhead I tolerate. It’s the checkpoint I want.

📖 Config you can actually read

When your configuration is a file, it is a file. It lives in git. It diffs. Someone can read the whole thing top to bottom and understand what this server does. Changes show up in a merge request review with hopefully useful comments explaining why. The flat file can be indented in places (especially the to lines in access controls) and is much easier for a human to read.

Now look at what cn=config leaves on disk. The slapd.d/ tree is a spray of generated LDIF with names like olcDatabase={1}mdb.ldif, carrying numeric ordering prefixes, entryUUIDs, timestamps, and a CRC checksum in a header that tells you, in the project’s own words, not to edit the file by hand. That warning is correct; the on-disk form was never meant for human eyes. To answer the simple question “what is this server’s configuration,” you don’t read a file, you slapcat the config database and interpret the dump. You can put slapd.d/ under version control, but you end up versioning a machine’s scratch space, and the diff stops telling you what a person changed and starts telling you what the backend rearranged. The flat file keeps the config’s canonical form the one you review.

🍰 Have your cake and eat it too

With the flat file, you can still have runtime changes for the handful of situations where it does make sense. In the flat file I always enable the config database itself, database config. That exposes cn=config on the running server for on-the-fly edits while the flat file stays the persistent source of truth, and it buys exactly the live moves worth having. I can raise olcLogLevel to chase a problem and drop it again without bouncing the server. One very good use of the OLC is short-lived TLS certificates: I can refresh slapd with a renewed TLS certificate, not changing any value, but just resetting it to the same one.

Because the configuration was loaded from the file and there is no slapd.d/ behind it, those live edits live in memory only. They vanish on restart and the server comes back up as the file I reviewed. The durable configuration is still the artifact in git; the live change is explicitly temporary, which is exactly what a live change should be.

The usual case for going all-in on cn=config instead is “I can’t afford the restart.” With the modern mdb backend a restart is cheap, and any directory serious enough to fear one already rolls restarts across replicas behind a load balancer without causing client impact. And replicating cn=config itself over syncrepl, sometimes pitched as the payoff, is the part I would argue hardest against: besides being a lot of unnecessary moving parts, it takes the one unreviewed keystroke and hands it the whole fleet, so a bad change lands everywhere at once with the checkpoint removed on every node. That is the blast radius sold as a feature.

😴 Boring, on purpose

None of this is a claim that cn=config is bad. It’s a claim that a static configuration file has real, present-tense virtues, reviewability and a built-in checkpoint. Trading them away should be a decision you make on purpose rather than a default you inherit because a man page said deprecated.

It ties straight back to the reliability trap: the directory you can still reason about years later is the one whose configuration you could read, diff, and talk about like the artifact it is. Keep the config flat, keep the live window narrow and temporary, and never confuse the option that saves you a restart today with the one that keeps you fluent for the outage you can’t see coming.

The flat file isn’t the old way I haven’t gotten around to leaving. It’s the checkpoint I chose to keep.

Running a directory you'd rather not think about? Talk to an expert More writing