FreeBSD.software
Home/Guides/OpenLDAP on FreeBSD: Directory Server Review
review·2026-04-09·10 min read

OpenLDAP on FreeBSD: Directory Server Review

Review of OpenLDAP on FreeBSD: slapd installation, schema configuration, ACLs, TLS, replication, and integration with SSH/sudo/PAM for centralized authentication.

OpenLDAP on FreeBSD: Directory Server Review

OpenLDAP provides a directory service for centralized authentication and authorization. If you manage more than a handful of FreeBSD servers and want consistent user accounts, SSH key distribution, sudo policies, and group management across all of them, LDAP is the answer. This review covers slapd installation on FreeBSD, schema configuration, access control, TLS encryption, replication for high availability, and practical integration with SSH, sudo, and PAM.

For related server security hardening practices, see our hardening FreeBSD server guide.

Why OpenLDAP in 2026

Active Directory dominates enterprise environments. FreeIPA is popular on Linux. But on FreeBSD, OpenLDAP remains the primary choice for LDAP-based directory services:

  • FreeIPA does not run on FreeBSD
  • OpenLDAP is well-packaged and maintained on FreeBSD
  • The nss_ldap and pam_ldap modules work reliably
  • It integrates with everything: SSH, sudo, Postfix, Dovecot, Squid, Samba, and more
  • It is lightweight compared to AD or IPA

If your infrastructure is FreeBSD-centric, OpenLDAP is the practical choice.

Installation

Binary Package

sh
pkg install openldap26-server openldap26-client

This installs slapd (the server), ldapsearch, ldapadd, ldapmodify, and other client tools.

Ports

sh
cd /usr/ports/net/openldap26-server make config # Enable modules you need: SASL, TLS, overlays make install clean

Initial Configuration

OpenLDAP uses OLC (On-Line Configuration), also called cn=config, as its configuration backend. This replaces the old slapd.conf file. However, for clarity and initial setup, many administrators still use slapd.conf and convert later.

Using slapd.conf (Traditional)

Create /usr/local/etc/openldap/slapd.conf:

sh
include /usr/local/etc/openldap/schema/core.schema include /usr/local/etc/openldap/schema/cosine.schema include /usr/local/etc/openldap/schema/inetorgperson.schema include /usr/local/etc/openldap/schema/nis.schema include /usr/local/etc/openldap/schema/misc.schema # Module path modulepath /usr/local/libexec/openldap moduleload back_mdb # Database definition database mdb maxsize 1073741824 suffix "dc=example,dc=com" rootdn "cn=admin,dc=example,dc=com" rootpw {SSHA}hashed_password_here directory /var/db/openldap-data # Indices for common searches index objectClass eq index uid eq,sub index cn eq,sub index mail eq index memberUid eq index uidNumber eq index gidNumber eq

Generate the root password hash:

sh
slappasswd -s "YourSecurePassword"

Copy the output into the rootpw line.

Set Permissions and Start

sh
# Create data directory mkdir -p /var/db/openldap-data chown ldap:ldap /var/db/openldap-data # Enable and start sysrc slapd_enable="YES" sysrc slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/"' service slapd start

Verify Installation

sh
ldapsearch -x -H ldap://localhost -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -W

Schema Configuration

Standard Schemas

The schemas included above (core, cosine, inetorgperson, nis) cover most use cases:

  • core.schema: Basic LDAP object classes
  • cosine.schema: X.500 attribute types
  • inetorgperson.schema: Person entries with email, phone, etc.
  • nis.schema: POSIX account attributes (uid, gid, home directory, shell)

For SSH public key distribution, add the OpenSSH LDAP schema:

sh
pkg install openssh-portable-ldap-pubkey

Or create a custom schema file:

sh
# /usr/local/etc/openldap/schema/openssh-lpk.schema attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DESC 'OPENSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DESC 'OPENSSH Public key objectclass' SUP top AUXILIARY MAY ( sshPublicKey $ uid ) )

Include it in slapd.conf:

sh
include /usr/local/etc/openldap/schema/openssh-lpk.schema

Populating the Directory

Base Structure

Create an LDIF file for the initial directory structure:

sh
# /tmp/base.ldif dn: dc=example,dc=com objectClass: dcObject objectClass: organization dc: example o: Example Organization dn: ou=People,dc=example,dc=com objectClass: organizationalUnit ou: People dn: ou=Groups,dc=example,dc=com objectClass: organizationalUnit ou: Groups dn: ou=Services,dc=example,dc=com objectClass: organizationalUnit ou: Services

Load it:

sh
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /tmp/base.ldif

Adding Users

sh
# /tmp/user.ldif dn: uid=jdoe,ou=People,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: ldapPublicKey uid: jdoe cn: John Doe sn: Doe givenName: John mail: jdoe@example.com uidNumber: 10001 gidNumber: 10001 homeDirectory: /home/jdoe loginShell: /bin/sh userPassword: {SSHA}hashed_password sshPublicKey: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... jdoe@workstation
sh
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /tmp/user.ldif

Adding Groups

sh
# /tmp/group.ldif dn: cn=sysadmins,ou=Groups,dc=example,dc=com objectClass: posixGroup cn: sysadmins gidNumber: 10001 memberUid: jdoe dn: cn=developers,ou=Groups,dc=example,dc=com objectClass: posixGroup cn: developers gidNumber: 10002 memberUid: jdoe
sh
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /tmp/group.ldif

Access Control Lists

ACLs control who can read, write, and modify directory entries.

sh
# /usr/local/etc/openldap/slapd.conf # Users can read and modify their own password # Admin can modify anything # Anonymous can authenticate (bind) # Authenticated users can read most attributes access to attrs=userPassword by self write by anonymous auth by dn="cn=admin,dc=example,dc=com" write by * none access to attrs=shadowLastChange by self write by dn="cn=admin,dc=example,dc=com" write by * read # SSH keys: readable by the service account access to attrs=sshPublicKey by dn="cn=sshd,ou=Services,dc=example,dc=com" read by self write by dn="cn=admin,dc=example,dc=com" write by * none # Default: authenticated users can read access to * by dn="cn=admin,dc=example,dc=com" write by users read by * none

Create a service account for sshd:

sh
# /tmp/service.ldif dn: cn=sshd,ou=Services,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: sshd userPassword: {SSHA}service_account_password

TLS Encryption

Never run LDAP without TLS in production. Passwords traverse the wire during bind operations.

Generate Certificates

sh
# Using a self-signed CA (use a real CA for production) mkdir -p /usr/local/etc/openldap/certs cd /usr/local/etc/openldap/certs # CA key and cert openssl req -new -x509 -nodes -days 3650 \ -keyout ca-key.pem -out ca-cert.pem \ -subj "/CN=LDAP CA" # Server key and CSR openssl req -new -nodes \ -keyout slapd-key.pem -out slapd.csr \ -subj "/CN=ldap.example.com" # Sign the server cert openssl x509 -req -days 3650 \ -in slapd.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out slapd-cert.pem # Set permissions chown ldap:ldap slapd-key.pem chmod 400 slapd-key.pem

Configure TLS in slapd.conf

sh
TLSCACertificateFile /usr/local/etc/openldap/certs/ca-cert.pem TLSCertificateFile /usr/local/etc/openldap/certs/slapd-cert.pem TLSCertificateKeyFile /usr/local/etc/openldap/certs/slapd-key.pem TLSProtocolMin 3.3 TLSCipherSuite HIGH:!aNULL:!MD5

Enable LDAPS

Update the slapd flags to listen on LDAPS (port 636):

sh
sysrc slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/ ldaps://0.0.0.0/"' service slapd restart

Require TLS

To reject non-TLS connections:

sh
# In slapd.conf security tls=1

Client TLS Configuration

On client machines, configure /usr/local/etc/openldap/ldap.conf:

sh
TLS_CACERT /usr/local/etc/openldap/certs/ca-cert.pem TLS_REQCERT demand URI ldaps://ldap.example.com BASE dc=example,dc=com

Replication

For high availability, configure replication between two or more slapd instances.

Provider-Consumer (Master-Slave)

On the provider (master), add to slapd.conf:

sh
moduleload syncprov overlay syncprov syncprov-checkpoint 100 10 syncprov-sessionlog 100

On the consumer (slave), add:

sh
syncrepl rid=001 provider=ldaps://ldap-master.example.com type=refreshAndPersist searchbase="dc=example,dc=com" scope=sub schemachecking=off bindmethod=simple binddn="cn=admin,dc=example,dc=com" credentials=AdminPassword starttls=critical tls_cacert=/usr/local/etc/openldap/certs/ca-cert.pem tls_reqcert=demand retry="60 +"

Multi-Master Replication

For active-active setups, both servers are providers and consumers of each other:

sh
# On server 1 serverID 1 syncrepl rid=001 provider=ldaps://ldap2.example.com # ... (same parameters as above) overlay syncprov # On server 2 serverID 2 syncrepl rid=002 provider=ldaps://ldap1.example.com # ... (same parameters as above) overlay syncprov

Multi-master replication works but requires careful conflict handling. Avoid simultaneous writes to the same entry on different masters.

PAM/NSS Integration

This is where LDAP becomes operationally useful: centralized login across all FreeBSD hosts.

Install Required Packages

sh
pkg install pam_ldap nss_ldap

Configure NSS

Edit /etc/nsswitch.conf:

sh
passwd: files ldap group: files ldap shadow: files ldap

Configure /usr/local/etc/nss_ldap.conf:

sh
uri ldaps://ldap.example.com base dc=example,dc=com binddn cn=nss,ou=Services,dc=example,dc=com bindpw service_password ssl on tls_cacertfile /usr/local/etc/openldap/certs/ca-cert.pem nss_base_passwd ou=People,dc=example,dc=com nss_base_group ou=Groups,dc=example,dc=com nss_base_shadow ou=People,dc=example,dc=com

Configure PAM

Edit /etc/pam.d/system or specific service files:

sh
# /etc/pam.d/sshd auth required pam_opie.so no_warn no_fake_prompts auth requisite pam_opieaccess.so no_warn allow_local auth sufficient /usr/local/lib/pam_ldap.so no_warn auth required pam_unix.so no_warn try_first_pass account sufficient /usr/local/lib/pam_ldap.so account required pam_unix.so password sufficient /usr/local/lib/pam_ldap.so password required pam_unix.so no_warn try_first_pass session required pam_unix.so

Home Directory Creation

Automatically create home directories on first login:

sh
# Add to /etc/pam.d/system or /etc/pam.d/sshd session required pam_mkhomedir.so mode=0700

Verify

sh
# Test NSS resolution getent passwd jdoe id jdoe # Test SSH login ssh jdoe@localhost

SSH Public Key Integration

Distribute SSH public keys via LDAP instead of managing authorized_keys files.

Configure sshd

Edit /usr/local/etc/ssh/sshd_config (if using openssh-portable):

sh
AuthorizedKeysCommand /usr/local/bin/ldap-ssh-keys.sh %u AuthorizedKeysCommandUser nobody

Create the key lookup script:

sh
#!/bin/sh # /usr/local/bin/ldap-ssh-keys.sh /usr/local/bin/ldapsearch -x -H ldaps://ldap.example.com \ -D "cn=sshd,ou=Services,dc=example,dc=com" \ -w "sshd_service_password" \ -b "ou=People,dc=example,dc=com" \ "(uid=$1)" sshPublicKey | \ sed -n 's/^sshPublicKey: //p'
sh
chmod 755 /usr/local/bin/ldap-ssh-keys.sh service sshd restart

Now, adding or revoking SSH keys in LDAP takes effect immediately on all servers. No need to touch authorized_keys files.

Sudo Integration

Centralize sudo rules in LDAP.

Add the Sudo Schema

sh
# The sudo schema is included with the sudo package pkg install sudo cp /usr/local/share/examples/sudo/schema.OpenLDAP /usr/local/etc/openldap/schema/sudo.schema

Add to slapd.conf:

sh
include /usr/local/etc/openldap/schema/sudo.schema

Add Sudo Rules to LDAP

sh
# /tmp/sudo.ldif dn: ou=SUDOers,dc=example,dc=com objectClass: organizationalUnit ou: SUDOers dn: cn=defaults,ou=SUDOers,dc=example,dc=com objectClass: sudoRole cn: defaults sudoOption: !authenticate sudoOption: env_keep += "SSH_AUTH_SOCK" dn: cn=sysadmins,ou=SUDOers,dc=example,dc=com objectClass: sudoRole cn: sysadmins sudoUser: %sysadmins sudoHost: ALL sudoCommand: ALL

Configure Sudo to Use LDAP

Edit /usr/local/etc/sudo-ldap.conf:

sh
uri ldaps://ldap.example.com sudoers_base ou=SUDOers,dc=example,dc=com binddn cn=sudo,ou=Services,dc=example,dc=com bindpw sudo_service_password ssl on tls_cacert /usr/local/etc/openldap/certs/ca-cert.pem

Edit /usr/local/etc/nsswitch.conf (or use /usr/local/etc/sudo.conf):

sh
sudoers: ldap files

Backup and Recovery

Database Export

sh
slapcat -b "dc=example,dc=com" > /backup/ldap-$(date +%Y%m%d).ldif

Database Import

sh
service slapd stop rm -rf /var/db/openldap-data/* slapadd -b "dc=example,dc=com" -l /backup/ldap-20260409.ldif chown -R ldap:ldap /var/db/openldap-data service slapd start

Automated Backups

sh
# /etc/cron.d/ldap-backup 0 3 * * * root /usr/local/sbin/slapcat -b "dc=example,dc=com" | gzip > /backup/ldap-$(date +\%Y\%m\%d).ldif.gz

Verdict

OpenLDAP on FreeBSD is the right tool for centralized authentication on FreeBSD-centric infrastructure. It is not glamorous, the configuration is verbose, and the learning curve is real. But once deployed, it eliminates the operational burden of managing user accounts, SSH keys, and sudo rules across multiple servers.

The PAM/NSS integration works. SSH key distribution works. Sudo integration works. TLS and replication work. It is battle-tested software that does what it claims.

The main risk is complexity. LDAP is not simple, and misconfiguration can lock you out of your own servers. Always maintain local root accounts as a fallback, and test changes in a staging environment first.

Rating: 7/10 -- Functionally excellent but held back by configuration complexity and the lack of a modern management interface. Consider supplementing with Apache Directory Studio or phpLDAPadmin for directory management.

Frequently Asked Questions

What happens if the LDAP server goes down?

If NSS/PAM cannot reach the LDAP server, users not in local /etc/passwd cannot log in. Mitigate this with:

  • Multi-master replication for redundancy
  • nss_ldap.conf setting bind_timelimit 5 to fail fast
  • Local root accounts that do not depend on LDAP
  • Consider nscd (name service caching daemon) to cache LDAP lookups

Should I use slapd.conf or cn=config (OLC)?

cn=config is the modern approach and supports runtime changes without restart. slapd.conf is easier to understand and version control. For small deployments (under 10 servers), slapd.conf is fine. For larger environments, invest in cn=config.

How do I migrate from NIS to LDAP?

Export NIS maps to LDIF format using ypcat and conversion scripts. The migrationtools package provides scripts for this:

sh
pkg install migrationtools /usr/local/share/migrationtools/migrate_passwd.pl /etc/passwd > passwd.ldif

Can I use LDAP with FreeBSD jails?

Yes. Configure each jail as an LDAP client. The jail does not need its own LDAP server -- it connects to the host's or a dedicated LDAP server. Ensure the jail has network access to the LDAP server and install pam_ldap and nss_ldap inside the jail.

How do I troubleshoot LDAP authentication failures?

sh
# Test LDAP connectivity ldapsearch -x -H ldaps://ldap.example.com -b "dc=example,dc=com" "(uid=jdoe)" # Test bind (authentication) ldapwhoami -x -H ldaps://ldap.example.com -D "uid=jdoe,ou=People,dc=example,dc=com" -W # Check slapd logs # Enable logging in slapd.conf: loglevel stats # Logs go to syslog facility local4 grep slapd /var/log/messages

What is the performance impact of LDAP authentication?

Negligible for authentication (a single LDAP bind per login). NSS lookups (getent passwd, group resolution) can be more frequent. Use nscd to cache results:

sh
sysrc nscd_enable="YES" service nscd start

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.