An OpenLDAP server without TLS is sending credentials in cleartext across your network. Every bind operation, every password change, every query with sensitive data is visible to anyone with a packet sniffer on the same subnet. Securing OpenLDAP with TLS is not optional for any environment that takes security seriously.
This guide walks through generating a private Certificate Authority, issuing a server certificate with Subject Alternative Names (SAN), configuring slapd for both STARTTLS (port 389) and LDAPS (port 636), and setting up a client machine to trust the CA and query over encrypted connections. We use self-signed certificates because LDAP servers are internal infrastructure. Unlike web servers, they don’t face the public internet, so Let’s Encrypt (which requires public DNS and HTTP validation) doesn’t apply here. Self-signed CA certs are the industry standard for internal LDAP deployments because you control both server and client and can distribute the CA cert to every machine that needs it.
Tested March 2026 | Ubuntu 24.04.4 LTS, OpenLDAP 2.6.10, two-node setup (server + client)
Prerequisites
Before starting, you need:
- A working OpenLDAP server on Ubuntu 24.04 or 22.04 with at least one user entry. If you haven’t set this up yet, follow our OpenLDAP installation guide for Ubuntu first
- A separate client machine (Ubuntu 24.04/22.04) with
ldap-utilsinstalled - Root or sudo access on both machines
- Server IP: 192.168.1.150 | Client IP: 192.168.1.151 (adjust to match your environment)
- OpenSSL installed on the server (included by default on Ubuntu)
- Tested on: Ubuntu 24.04.4 LTS with OpenLDAP 2.6.10
Server Side: Generate TLS Certificates
All certificate generation happens on the LDAP server (192.168.1.150). We’ll create a private CA, then use it to sign a server certificate. This gives you full control over the trust chain without depending on any external certificate authority.
Create the Certificate Directory
Store all TLS files in /etc/ldap/tls/ to keep them separate from the main slapd configuration:
sudo mkdir -p /etc/ldap/tls
cd /etc/ldap/tls
Generate the CA Key and Certificate
The CA (Certificate Authority) is the root of trust. Every client that trusts this CA will automatically trust any certificate signed by it. Generate a 4096-bit RSA key and a self-signed CA certificate valid for 10 years:
sudo openssl genrsa -out ca.key 4096
Now create the CA certificate:
sudo openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=US/ST=State/L=City/O=Example Inc/CN=Example CA"
Replace the subject fields (C, ST, L, O, CN) with your organization’s actual details. The CN for the CA should identify it as a CA, not the server hostname.
Generate the Server Key and CSR with SAN
Modern OpenSSL versions have deprecated CN-only matching for certificate validation. You must include Subject Alternative Names (SAN) with both the hostname and IP address. Without SAN entries, TLS clients will reject the certificate.
Generate the server private key:
sudo openssl genrsa -out server.key 4096
Create an OpenSSL configuration file for the CSR that includes the SAN extension:
sudo vi /etc/ldap/tls/server.cnf
Add the following configuration. Update CN, DNS.1, and IP.1 to match your LDAP server’s hostname and IP:
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
[dn]
C = US
ST = State
L = City
O = Example Inc
CN = ldap.example.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = ldap.example.com
IP.1 = 192.168.1.150
Generate the Certificate Signing Request using this config file:
sudo openssl req -new -key server.key -out server.csr -config server.cnf
Sign the Server Certificate with the CA
Sign the CSR with your CA, copying the SAN extensions into the final certificate. The -extfile and -extensions flags ensure the SAN entries make it into the signed cert:
sudo openssl x509 -req -days 3650 -in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -extfile server.cnf -extensions v3_req
Verify the certificate has the correct subject, issuer, and SAN entries:
openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName
The output should confirm the SAN includes both the DNS name and IP address:
subject=C = US, ST = State, L = City, O = Example Inc, CN = ldap.example.com
issuer=C = US, ST = State, L = City, O = Example Inc, CN = Example CA
notBefore=Mar 27 09:47:03 2026 GMT
notAfter=Mar 24 09:47:03 2036 GMT
X509v3 Subject Alternative Name:
DNS:ldap.example.com, IP Address:192.168.1.150
Set File Ownership
The slapd process runs as the openldap user. It must be able to read the certificate files and the private key:
sudo chown openldap:openldap /etc/ldap/tls/*
sudo chmod 600 /etc/ldap/tls/server.key
sudo chmod 644 /etc/ldap/tls/server.crt /etc/ldap/tls/ca.crt
The private key gets 600 (owner read/write only), while the certificate and CA cert can be world-readable since they contain no secrets.
Server Side: Configure slapd for TLS
With the certificates in place, tell slapd where to find them. OpenLDAP uses its cn=config database for runtime configuration, so we apply changes via an LDIF file.
Apply TLS Configuration to slapd
Create the LDIF file that sets the certificate paths:
sudo vi /tmp/tls-config.ldif
Add the following content:
dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/tls/ca.crt
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/tls/server.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/tls/server.key
Apply it using ldapmodify with EXTERNAL SASL authentication (which authenticates as root via Unix socket):
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/tls-config.ldif
You should see the modification applied successfully:
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"
If you get an error about the attributes already existing, use replace instead of add in the LDIF. This happens when TLS was partially configured before.
Enable LDAPS (Port 636)
By default, slapd only listens on ldap:// (port 389). To enable LDAPS on port 636, edit the slapd defaults file:
sudo vi /etc/default/slapd
Find the SLAPD_SERVICES line and add ldaps:///:
SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
Restart slapd to pick up the changes:
sudo systemctl restart slapd
Confirm slapd is now listening on both ports 389 and 636:
sudo ss -tlnp | grep slapd
Both LDAP and LDAPS ports should be active:
LISTEN 0 2048 0.0.0.0:636 0.0.0.0:* users:(("slapd",pid=12702,fd=11))
LISTEN 0 2048 0.0.0.0:389 0.0.0.0:* users:(("slapd",pid=12702,fd=8))
Configure the Server’s LDAP Client Settings
The LDAP client tools on the server itself (ldapsearch, ldapwhoami) also need to know about the CA certificate. Edit the system-wide LDAP client configuration:
sudo vi /etc/ldap/ldap.conf
Add or update these lines:
BASE dc=example,dc=com
URI ldap://192.168.1.150
TLS_CACERT /etc/ldap/tls/ca.crt
The TLS_CACERT directive tells all LDAP client tools to trust certificates signed by your CA.
Test TLS from the Server
Run a STARTTLS query (upgrades port 389 to encrypted):
ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150 -ZZ
The -ZZ flag requires STARTTLS to succeed or the command fails. Enter the admin password when prompted:
dn:cn=admin,dc=example,dc=com
Now test LDAPS (dedicated encrypted port 636):
ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150
Same result confirms LDAPS is working:
dn:cn=admin,dc=example,dc=com
Both protocols are functional. STARTTLS upgrades an existing connection on port 389, while LDAPS establishes a TLS connection from the start on port 636. Most modern setups prefer LDAPS because it’s simpler to firewall (just allow 636, block 389).
Client Side: Configure TLS
Switch to the client machine (192.168.1.151) for the remaining steps. The client needs the CA certificate to verify the server’s identity during the TLS handshake.
Copy the CA Certificate to the Client
From the client machine, pull the CA certificate from the server using scp:
scp [email protected]:/etc/ldap/tls/ca.crt /tmp/ldap-ca.crt
Install it into the system certificate store so all applications (not just LDAP tools) can use it:
sudo cp /tmp/ldap-ca.crt /usr/local/share/ca-certificates/ldap-ca.crt
sudo update-ca-certificates
This adds the CA to Ubuntu’s trusted certificate bundle. The update-ca-certificates command regenerates /etc/ssl/certs/ca-certificates.crt, which is the system-wide trust store.
Configure the LDAP Client
Install the LDAP client utilities if they’re not already present:
sudo apt install -y ldap-utils
Edit the client’s LDAP configuration file:
sudo vi /etc/ldap/ldap.conf
Set the base DN, server URI, and CA certificate path:
BASE dc=example,dc=com
URI ldaps://192.168.1.150
TLS_CACERT /usr/local/share/ca-certificates/ldap-ca.crt
Notice the URI uses ldaps:// here. The client will connect over encrypted LDAPS by default for all LDAP queries.
Test LDAPS from the Client
Verify admin authentication over LDAPS:
ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150
Enter the admin password. The response confirms encrypted authentication is working from the client:
dn:cn=admin,dc=example,dc=com
Test with a regular user account as well:
ldapwhoami -x -D "uid=jdoe,ou=people,dc=example,dc=com" -W -H ldaps://192.168.1.150
User authentication works over the encrypted channel:
dn:uid=jdoe,ou=people,dc=example,dc=com
Run a full search to confirm data retrieval over LDAPS:
ldapsearch -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150 \
-b "dc=example,dc=com" "(uid=jdoe)" cn uid homeDirectory
The search returns the user’s attributes over the encrypted connection:
dn: uid=jdoe,ou=people,dc=example,dc=com
cn: John Doe
uid: jdoe
homeDirectory: /home/jdoe
Test STARTTLS from the Client
STARTTLS works from the client too. Use the -ZZ flag against port 389:
ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150 -ZZ
This should return the same admin DN, confirming STARTTLS negotiation succeeded from the client machine.
Verify the Certificate Chain with OpenSSL
For a deeper verification, connect with openssl s_client and inspect the TLS handshake directly:
openssl s_client -connect 192.168.1.150:636 -CAfile /usr/local/share/ca-certificates/ldap-ca.crt /dev/null | grep -E "subject=|issuer=|Verify"
A successful verification looks like this:
subject=C = US, ST = State, L = City, O = Example Inc, CN = ldap.example.com
issuer=C = US, ST = State, L = City, O = Example Inc, CN = Example CA
Verify return code: 0 (ok)
Verify return code: 0 (ok) means the entire certificate chain validated successfully. The server cert was signed by the CA, and the client trusts that CA.
Enforce TLS for All Connections (Optional)
At this point, TLS is available but not required. Clients can still bind over unencrypted LDAP on port 389 without STARTTLS. To force all connections to use encryption, set the olcSecurity attribute on the server.
Back on the server (192.168.1.150), create the enforcement LDIF:
sudo vi /tmp/enforce-tls.ldif
Add the following:
dn: cn=config
changetype: modify
add: olcSecurity
olcSecurity: tls=1
Apply it:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/enforce-tls.ldif
After applying this, any client that attempts a simple bind on port 389 without first issuing STARTTLS will get a “Confidentiality required” error. LDAPS connections on port 636 are unaffected since they’re encrypted from the start.
Test that enforcement works by trying an unencrypted bind:
ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150
This should fail with ldap_bind: Confidentiality required (13). Adding -ZZ or switching to ldaps:// will succeed as before.
Important: Only enable enforcement after confirming that ALL clients have been updated with the CA certificate and are configured to use TLS. Otherwise, you’ll lock out applications that haven’t been migrated yet.
Ubuntu 22.04 Notes
The steps in this guide apply to Ubuntu 22.04 LTS as well. The main difference is that Ubuntu 22.04 ships with OpenLDAP 2.5.x instead of 2.6.10, but the TLS configuration directives (olcTLSCACertificateFile, olcTLSCertificateFile, olcTLSCertificateKeyFile) are identical across both versions. The file paths, ownership requirements, and /etc/default/slapd configuration are the same.
One thing to watch for: Ubuntu 22.04’s OpenSSL version (3.0.x) already enforces SAN validation, so the SAN configuration in the server.cnf file is equally critical on 22.04. Do not skip it, even on the older release.
Troubleshooting
Error: “TLS: can’t accept: No certificate was found.”
The openldap user cannot read the certificate or key files. Check ownership and permissions:
ls -la /etc/ldap/tls/
All files should be owned by openldap:openldap. The key file needs 600 permissions. Fix with sudo chown openldap:openldap /etc/ldap/tls/* and restart slapd.
Error: “ldap_sasl_bind: Can’t contact LDAP server (-1)” on port 636
slapd isn’t listening on port 636. Verify the SLAPD_SERVICES line in /etc/default/slapd includes ldaps:/// (with three slashes, not two). After editing, restart slapd and check with sudo ss -tlnp | grep 636.
Error: “TLS: hostname does not match CN in peer certificate”
The server certificate’s SAN doesn’t include the hostname or IP you’re connecting with. Regenerate the certificate with the correct DNS.1 and IP.1 entries in the server.cnf file. If you connect by IP, IP.1 must be present. If you connect by hostname, DNS.1 must match exactly.
Error: “TLS: peer cert untrusted or revoked”
The client doesn’t trust the CA that signed the server certificate. Verify that TLS_CACERT in /etc/ldap/ldap.conf points to the correct CA certificate file and that the file is readable. On the client, also confirm update-ca-certificates was run after copying the CA cert.
STARTTLS vs LDAPS: Which to Use
Both STARTTLS and LDAPS encrypt the connection. The difference is when encryption begins:
| Feature | STARTTLS (port 389) | LDAPS (port 636) |
|---|---|---|
| Encryption start | Upgrades after initial plaintext connection | Encrypted from the first byte |
| Port | 389 (shared with unencrypted LDAP) | 636 (dedicated) |
| Firewall simplicity | Harder (same port for encrypted and unencrypted) | Easier (block 389, allow only 636) |
| Downgrade risk | Possible if client doesn’t enforce with -ZZ | None |
| Industry trend | Being phased out | Preferred for new deployments |
For new deployments, LDAPS on port 636 is the cleaner choice. You can disable port 389 entirely by removing ldap:/// from SLAPD_SERVICES once all clients are migrated to LDAPS. Keep ldapi:/// (the Unix socket) for local administration.
Going Further
With TLS secured, here are logical next steps for hardening your LDAP infrastructure:
- Client certificate authentication (mTLS) requires clients to present their own certificates, adding a second layer of verification beyond passwords
- Restrict TLS versions by setting
olcTLSProtocolMinto3.3(TLS 1.2) or3.4(TLS 1.3) to block older, weaker protocols - Cipher suite hardening with
olcTLSCipherSuiteto disable weak ciphers and enforce forward secrecy - LDAP access control lists (ACLs) to restrict who can read sensitive attributes like
userPassword - Certificate rotation with a cron job or reminder system, since 10-year validity is convenient but shorter lifetimes (1-2 years) are more secure
Running Ubuntu 20.04 I was having issues getting this to work.
Got error: “wrong attributetype at line 5 entry cn=config”
Modified the ldap_ssl.ldif file to separate the modify lines and it worked.
# vim ldap_ssl.ldif
dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/sasl2/ca-certificates.crt
–
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/sasl2/ldap_server.crt
–
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/sasl2/ldap_server.key
Thanks for the comment we’ve updated the article.
Hi Josphat,
Here is typo in line: Add LS_REQCERT allow line to /etc/ldap/ldap.conf.
Article has been updated. Thanks for sharing the typo.
i am still having an issue with when trying to execute ” ldapmodify -Y EXTERNAL -H ldapi:/// -f fnc-ldap-ssl.ldif ”
ERROR:
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
ldapmodify: invalid format (line 5) entry: “cn=config”
From where does this file come from? – /etc/ldap/sasl2/ca-certificates.crt
In the article, it only exists from the copy section.
Hello @Anurag Ray
The certs were generated and copied to /etc/ldap/sasl2/ then used in the config.
kind of confused about the very last command.
“Now configure OpenLDAP SSL mechanism by uncommenting the lines below”
where can I find it sudo nano /etc/ldap.conf ?
You might consider re-reading this part, it is well explained. Use nano if you prefer it to vim just like me, but you got the point:
– edit the file /etc/ldap.conf
– Uncomment THESES lines… ie:
– ssl start_tls
– ssl on
Then save your file
Don’t get me wrong its a great article I defiantly learn from it but I never got it to work
when I run
$ ldapwhoami -x -H ldaps://ldap.example.com
I get ldap_sasl_bind(SIMPLE): Can’t contact LDAP server (-1)