LDAP HOWTO: OpenLDAP, 389 Directory Server, FreeIPA and SSSD

Updated November 2026

LDAP (Lightweight Directory Access Protocol) stores users, groups and other records in a tree that every machine on the network can query. On Linux today you run the directory with OpenLDAP, 389 Directory Server or FreeIPA, and clients log in through SSSD. This page shows a working setup for each, with real commands and LDIF.

The classic LDAP Implementation HOWTO (2001) used pam_ldap and nss_ldap, which are long gone; the Linux Documentation Project still keeps its related LDAP-HOWTO at tldp.org. Versions below are as of November 2026.

Choose a server

LDAP servers on Linux
ServerCurrent versionsWhere it is packaged
OpenLDAP (slapd)2.6 (long-term support) and 2.7 (feature release)Debian 13 (2.6.10), Ubuntu, Fedora (openldap-servers). Not on RHEL 8 and later: Red Hat removed openldap-servers; the client tools remain.
389 Directory Server3.xFedora and Debian (389-ds-base); on RHEL as part of IdM, or as the separately sold Red Hat Directory Server
FreeIPA (RHEL IdM)4.xServer on Fedora and RHEL family; Debian 13 ships only freeipa-client

If what you need is central logins for Linux machines, FreeIPA is usually the shortest path: it bundles 389 Directory Server, MIT Kerberos, a certificate authority and optional DNS, and joins clients in one command. Choose plain OpenLDAP or 389 DS when you need a general directory for applications, or a small server that only speaks LDAP.

OpenLDAP on Debian and Ubuntu

sudo apt install slapd ldap-utils
sudo dpkg-reconfigure slapd

dpkg-reconfigure asks for the DNS domain (which becomes the base DN, for example example.com → dc=example,dc=com), the organization name and the admin password. The admin entry is cn=admin,dc=example,dc=com.

cn=config: configuration is data

Modern slapd keeps its configuration as LDAP entries under cn=config, stored in /etc/ldap/slapd.d/ on Debian. The OpenLDAP admin guide says never to edit those LDIF files directly; change them with ldapmodify. On Debian, root can do that over the local socket (ldapi:///) with SASL EXTERNAL, without any password:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn

The main database appears as olcDatabase={1}mdb,cn=config. To add an equality index on mail, save this as index.ldif:

dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: mail eq
sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f index.ldif

The change takes effect immediately; there is no restart.

Add users and groups

Save this as add_content.ldif. The posixAccount and posixGroup classes hold the Unix fields (UID, GID, home, shell) that SSSD needs:

dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

dn: cn=staff,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: staff
gidNumber: 5000
memberUid: alice

dn: uid=alice,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: alice
cn: Alice Example
sn: Example
givenName: Alice
mail: alice@example.com
uidNumber: 10000
gidNumber: 5000
homeDirectory: /home/alice
loginShell: /bin/bash
ldapadd -x -D cn=admin,dc=example,dc=com -W -f add_content.ldif
ldappasswd -x -D cn=admin,dc=example,dc=com -W -S uid=alice,ou=People,dc=example,dc=com
ldapsearch -x -LLL -H ldap://localhost -b dc=example,dc=com '(uid=alice)' cn uidNumber
ldapwhoami -x -D uid=alice,ou=People,dc=example,dc=com -W

Blank lines separate entries, and parents must exist before children, so the order above matters. ldappasswd -S prompts for the new password and stores it hashed. Pick UID and GID numbers above the local range (10000 and up is common) so they never collide with accounts in /etc/passwd.

Turn on TLS

Clients must not send passwords in clear text, and SSSD refuses to authenticate over an unencrypted connection. Give slapd a certificate (see the SSL certificates HOWTO) by setting olcTLSCertificateFile, olcTLSCertificateKeyFile and olcTLSCACertificateFile on cn=config in one ldapmodify, making sure the openldap user can read the key. Then test StartTLS from a client:

ldapsearch -x -ZZ -H ldap://ldap.example.com -b dc=example,dc=com '(uid=alice)'

-ZZ makes the search fail unless StartTLS succeeds. Open port 389 (and 636 for LDAPS) with sudo firewall-cmd --permanent --add-service=ldap --add-service=ldaps or the matching ufw rule.

389 Directory Server

389 DS is configured with its own tools instead of hand-written LDIF for cn=config. On Fedora (or Debian with apt install 389-ds-base):

sudo dnf install 389-ds-base

Describe the instance in /root/instance.inf:

[general]
config_version = 2

[slapd]
root_password = <directory-manager-password>

[backend-userroot]
sample_entries = yes
suffix = dc=example,dc=com
sudo dscreate from-file /root/instance.inf
sudo dsctl localhost status
sudo dsidm localhost user create --uid alice --cn "Alice Example" --displayName "Alice Example" \
     --uidNumber 10000 --gidNumber 5000 --homeDirectory /home/alice
sudo dsidm localhost group create          # asks for the group name

sample_entries = yes adds a basic set of example entries under the suffix. With this file the instance is called localhost, the name the dsctl and dsidm commands take; root_password is the password of the directory’s administrative root account (cn=Directory Manager), so delete /root/instance.inf or remove the line once the instance exists.

FreeIPA: directory plus Kerberos

On a fresh Fedora or RHEL-family server with a static, fully qualified host name that resolves forward and backward:

sudo dnf install freeipa-server            # RHEL, Alma, Rocky: ipa-server
sudo ipa-server-install
sudo firewall-cmd --permanent --add-service=freeipa-4
sudo firewall-cmd --reload
kinit admin
ipa user-add alice --first=Alice --last=Example
ipa passwd alice

The installer refuses localhost and short names, and wants the full name first in /etc/hosts (for example 10.0.0.1 ipa.example.test ipa). FreeIPA’s guide suggests a domain you control or a reserved test domain, not someone else’s. The password set by ipa passwd is temporary and must be changed at first login.

Join each client, including Debian and Ubuntu machines with freeipa-client installed:

sudo ipa-client-install --mkhomedir

It configures SSSD, Kerberos (/etc/krb5.conf), /etc/nsswitch.conf, time sync and SSH in one go. Nothing in the next section is needed for IPA clients.

Linux clients with SSSD

For a plain LDAP server (OpenLDAP or 389 DS), configure SSSD yourself. It replaces nss_ldap, pam_ldap and nslcd; Red Hat removed nss-pam-ldapd in RHEL 9 and points users to SSSD’s LDAP provider.

# Debian / Ubuntu
sudo apt install sssd-ldap libnss-sss libpam-sss
# Fedora / RHEL
sudo dnf install sssd sssd-ldap oddjob-mkhomedir

Create /etc/sssd/sssd.conf:

[sssd]
services = nss, pam
domains = example

[domain/example]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://ldap.example.com
ldap_search_base = dc=example,dc=com
ldap_id_use_start_tls = true
ldap_tls_reqcert = demand
ldap_tls_cacert = /etc/ssl/certs/example-ca.pem
cache_credentials = true

The file must be a regular file owned by root and readable and writable only by root, or SSSD will not start:

sudo chown root:root /etc/sssd/sssd.conf
sudo chmod 600 /etc/sssd/sssd.conf
sudo systemctl enable --now sssd
sudo systemctl restart sssd

Then wire it into NSS and PAM:

# Fedora / RHEL
sudo authselect select sssd with-mkhomedir
sudo systemctl enable --now oddjobd
# Debian / Ubuntu (libnss-sss and libpam-sss already enabled the "sss" profile)
sudo pam-auth-update --enable mkhomedir

Test it:

getent passwd alice
id alice
su - alice
sudo sss_cache -E          # clear SSSD’s cache after changes in the directory

If the server does not allow anonymous searches, add ldap_default_bind_dn, ldap_default_authtok_type = password and ldap_default_authtok with a read-only service account.

Mistakes to avoid

Sources