Manage, Renew, and Back Up 389 Directory Server Certificates

Inventory, renew, replace, back up, and restore 389 Directory Server TLS certificates in the instance NSS database after LDAPS and STARTTLS are already enabled.

Published

Updated

Read time 26 min read

Reviewed byDeepak Prasad

389 Directory Server NSS certificate database with server certificate renewal, CA chain, and LDAPS backup workflow

389 Directory Server stores server certificates, CA certificates, and private keys in an instance-specific NSS database under the configuration directory. Nicknames such as Server-Cert identify entries inside that database; trust flags tell NSS how to treat CA material; and the active server nickname (nsSSLPersonalitySSL) decides which certificate LDAPS and STARTTLS present to clients.

This guide covers the full certificate lifecycle after TLS is already working: inventory, expiry checks, backup, CSR generation, renewal and replacement, CA chain maintenance, nickname changes, NSS password handling, safe removal, and recovery from expired or broken material.

Before you start:

IMPORTANT
This guide covers certificate and NSS database management after TLS is enabled. It does not repeat initial LDAPS or STARTTLS setup (TLS chapter), TLS version and cipher tuning, mandatory secure binds, or client-certificate authentication. If attribute encryption is enabled, read attribute encryption before you replace Server-Cert.

Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.

The lab uses instance ldap1 on ldap1.example.com (LDAP 389, LDAPS 636) and a second instance ldap2 on ports 1389 and 1636, each with its own NSS database under /etc/dirsrv/slapd-<instance>/.


Understand the Directory Server certificate store

Component Purpose
Server certificate Identifies the LDAP server to TLS clients
Private key Proves ownership of the server certificate
CA certificate Lets Directory Server and clients validate the issuing authority
Intermediate CA Connects the server certificate to a trusted root
Certificate nickname Names a certificate or key pair inside the NSS database
Trust flags Define how NSS trusts a CA certificate (see table below)
NSS database Stores certificates and private keys (cert9.db, key4.db)
pwdfile.txt Supplies the NSS database password to administrative tools
pin.txt Supplies the token name and NSS password when Directory Server starts
Flags Meaning
c,, Recognize the certificate as a valid CA without necessarily making it an explicit trust anchor
C,, Trust the CA to issue server or replication-peer certificates
T,, Trust the CA to issue client certificates
CT,, Trust the CA for both server and client-certificate validation

Give the root or intended trust anchor C,, when it is trusted to issue server certificates. Intermediate certificates commonly use c,, so NSS recognizes them as valid CA certificates without automatically treating every intermediate as a trust anchor. Add T only when the CA is authorized to issue client certificates used for TLS EXTERNAL authentication.

The NSS database is created during instance setup and lives with the instance configuration:

text
/etc/dirsrv/slapd-INSTANCE/

Typical files in that directory include cert9.db, key4.db, pin.txt, pwdfile.txt, ca.crt, and Server-Cert.crt. After you generate a renewal request, Server-Cert.csr appears as well. A dscreate instance on the same host may share a host-level signing CA under /etc/dirsrv/ssca/ while each instance keeps its own NSS store.

dscreate stores the NSS password in pwdfile.txt for administrative tools and in pin.txt for automatic token unlock at instance startup. Both files are created during instance setup.


List installed certificates

Start with the supported Directory Server tools. They read the same NSS database the server uses at runtime.

List server certificates in the instance NSS database:

bash
dsconf ldap1 security certificate list

Sample output:

output
Certificate Name: Server-Cert
Subject DN: CN=ldap1.example.com,givenName=6d6a490c-bebd-41c4-8552-20cb270367ed,O=testing,L=389ds,ST=Queensland,C=AU
Issuer DN: CN=ssca.389ds.example.com,O=testing,L=389ds,ST=Queensland,C=AU
Expires: 2028-07-15 08:12:48
Trust Flags: u,u,u

List installed CA certificates and inspect their trust flags:

bash
dsconf ldap1 security ca-certificate list

Sample output:

output
Certificate Name: Self-Signed-CA
Subject DN: CN=ssca.389ds.example.com,O=testing,L=389ds,ST=Queensland,C=AU
Issuer DN: CN=ssca.389ds.example.com,O=testing,L=389ds,ST=Queensland,C=AU
Expires: 2028-07-15 06:33:15
Trust Flags: C,,

Show the certificate clients receive on LDAPS and STARTTLS:

bash
dsctl ldap1 tls show-server-cert

The command prints the full PEM details, including serial number, validity, SAN entries, and fingerprints. In this lab the active entry is Server-Cert with SAN ldap1.example.com.

For one nickname, dsconf security certificate get returns a shorter summary:

bash
dsconf ldap1 security certificate get Server-Cert

Sample output:

output
Certificate Name: Server-Cert
Subject DN: CN=ldap1.example.com,givenName=6d6a490c-bebd-41c4-8552-20cb270367ed,O=testing,L=389ds,ST=Queensland,C=AU
Issuer DN: CN=ssca.389ds.example.com,O=testing,L=389ds,ST=Queensland,C=AU
Expires: 2028-07-15 08:12:48
Trust Flags: u,u,u

Confirm whether each server certificate has a matching private key:

bash
dsconf ldap1 security key list

Sample output:

output
Cipher:  rsa
Key Id: 5f2a98f53c0b3ce916e05bac228e517ae11f7b57
State: NSS Certificate DB:Server-Cert

A State of (orphan) means a private key exists without a linked certificate nickname. That is common after generate-server-cert-csr until the signed certificate is imported.

For the local ldap2 instance, use the instance name when local resolution is configured:

bash
dsconf ldap2 security certificate list

On the tested lab build, that command can fail against ldap2 with expected str, bytes or os.PathLike object, not NoneType while ldap1 succeeds. When dsconf cannot list server certificates, inspect the local NSS database instead:

bash
certutil -L -d /etc/dirsrv/slapd-ldap2/

Sample output:

output
Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

Self-Signed-CA                                               CT,,
Server-Cert                                                  u,u,u

Then confirm which certificate ldap2 would present on LDAPS:

bash
dsctl ldap2 tls show-server-cert

To target the non-default LDAPS listener explicitly, supply the LDAP URL and read the Directory Manager password from a file with -y:

bash
LDAPTLS_CACERT=/root/ldap2-ca-chain.pem dsconf -D "cn=Directory Manager" -y /root/dm.pw ldaps://ldap2.example.com:1636 security certificate list

RHDS distinguishes local instance-name resolution from explicitly supplied LDAP URLs. When dsconf cannot reach a remote listener, inspect the local NSS database with dsctl ldap2 tls show-server-cert or certutil -L -d /etc/dirsrv/slapd-ldap2/.

Recent dsconf and dsctl builds add options over time; run --help on your installed version before you script nickname selection.


Check certificate expiration

Inspect the active server certificate locally:

bash
dsctl ldap1 tls show-server-cert

Read the Not Before and Not After lines and confirm the DNS name SAN covers the hostname clients use.

Inspect only the leaf certificate the listener presents with OpenSSL:

bash
openssl s_client -connect ldap1.example.com:636 -servername ldap1.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -serial -ext subjectAltName

Sample output:

output
subject=C=AU, ST=Queensland, L=389ds, O=testing, GN=6d6a490c-bebd-41c4-8552-20cb270367ed, CN=ldap1.example.com
issuer=C=AU, ST=Queensland, L=389ds, O=testing, CN=ssca.389ds.example.com
notBefore=Jul 15 08:12:48 2026 GMT
notAfter=Jul 15 08:12:48 2028 GMT
serial=CAD43C73
X509v3 Subject Alternative Name:
    DNS:ldap1.example.com

That pipeline shows leaf details only; it does not validate the complete chain.

Before renewal, record:

  • Expiration date and remaining window
  • SAN hostname coverage
  • Issuer and complete chain files on disk
  • Active nickname (dsconf ldap1 security rsa get)
  • Client trust store contents for applications that pin CAs

Back up certificates before making changes

Current RHDS 13 backups created by dsconf backup create or dsctl db2bak include the instance configuration, NSS certificate database, and custom schema under the backup's config_files/ directory. Those configuration files are backed up but are not restored automatically with the database. Keep an additional off-host PKCS#12 export and verify every backup contains cert9.db, key4.db, and the required configuration files.

dsconf backup create is the online method; dsctl db2bak is offline.

Create an online backup:

bash
dsconf ldap1 backup create

Sample output:

output
The backup create task has finished successfully

List the backed-up configuration files to confirm NSS material is present:

bash
ls /var/lib/dirsrv/slapd-ldap1/bak/ldap1-*/config_files/

Sample output:

output
cert9.db
certmap.conf
dse.ldif
key4.db
pin.txt
pwdfile.txt
schema
slapd-collations.conf

In a replicated deployment, restoring an online backup clears the replication changelog and requires the replica to be reinitialized. Use an offline dsctl INSTANCE db2bak backup when avoiding that recovery step is important, accepting the required downtime.

WARNING
Do not import, remove, or modify certificates while the backup is running. Red Hat warns that changing the certificate database during backup can leave the backed-up NSS database inconsistent.

A direct tar command archive can remain as a supplemental host-level backup. Stop the instance first so NSS files are not changing during the archive:

bash
dsctl ldap1 stop

I'll set umask 077 before creating the archive so new files are not world-readable:

bash
umask 077

Create the archive with ACLs, extended attributes, and SELinux labels preserved:

bash
tar --acls --xattrs --selinux -czpf /root/slapd-ldap1-config-$(date +%F-%H%M).tar.gz -C /etc/dirsrv slapd-ldap1

I'll set mode 600 on the finished archive with the chmod command because it contains private keys and NSS password files:

bash
chmod 600 /root/slapd-ldap1-config-*.tar.gz

Start the instance again after the backup completes:

bash
dsctl ldap1 start

Also record in your change-management system:

  • Current server certificate nickname
  • CA trust flags
  • dsconf ldap1 security rsa get output
  • Certificate fingerprints from dsctl ldap1 tls show-server-cert
  • Location of PKCS#12 and backup archives (not the plaintext NSS password)

Export the server certificate and private key

Export the active server certificate and private key into a password-protected PKCS#12 file with pk12util. Store the export password in a file and pass it with lowercase -w (read password from file). Pass the NSS token password with lowercase -k (read from file):

bash
install -m 600 /dev/null /root/pk12-export.pw

Write the export password into /root/pk12-export.pw with an editor, then export:

bash
pk12util -d /etc/dirsrv/slapd-ldap1 -n "Server-Cert" -o /root/ldap1-server-cert-backup.p12 -w /root/pk12-export.pw -k /etc/dirsrv/slapd-ldap1/pwdfile.txt

Sample output:

output
pk12util: PKCS12 EXPORT SUCCESSFUL

I'll set mode 600 on the PKCS#12 export because it contains the private key:

bash
chmod 600 /root/ldap1-server-cert-backup.p12

Store the .p12 password in an approved secret manager. The export contains the selected certificate and private key. It may also contain certificates from a chain that NSS can build, but do not rely on that without checking pk12util -l. Preserve CA and intermediate certificates separately as well.

List the export contents when you need to verify:

bash
pk12util -l /root/ldap1-server-cert-backup.p12 -w /root/pk12-export.pw

Sample output:

output
Key(shrouded):
    Friendly Name: Server-Cert
...
Certificate:
    Data:
        Version: 3 (0x2)
...
    Friendly Name: Server-Cert

Exact formatting varies by NSS version; confirm that both a certificate and a private key entry appear.

Export only the public certificate PEM when you do not need the private key:

bash
dsctl ldap1 tls export-cert Self-Signed-CA --output-file /root/self-signed-ca.pem

That command exits silently on success; the PEM file should begin with -----BEGIN CERTIFICATE-----.


Generate a certificate renewal CSR

I'll generate a new key pair and CSR inside the instance NSS database:

bash
dsctl ldap1 tls generate-server-cert-csr --subject "CN=ldap1.example.com,O=Example" ldap1.example.com

Sample output:

output
/etc/dirsrv/slapd-ldap1/Server-Cert.csr

The CSR file lands in the instance configuration directory; the matching private key stays in key4.db until you import the signed certificate.

Review the CSR before you submit it to the CA:

bash
openssl req -in /etc/dirsrv/slapd-ldap1/Server-Cert.csr -noout -text

Sample output:

output
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: O=Example, CN=ldap1.example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
...
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:ldap1.example.com

Confirm the common name, SAN list, and key size match your CA request template.

This command writes a new private key into the NSS database. Do not run it while another backup, certificate import, PKCS#12 operation, or NSS maintenance task is modifying the same database.

dsconf can list and display CSRs as well. List pending CSRs in the instance NSS database:

bash
dsconf ldap1 security csr list

Show the CSR details for the Server-Cert nickname:

bash
dsconf ldap1 security csr get Server-Cert

After the CA returns a signed certificate, delete the CSR file when you no longer need it:

bash
dsconf ldap1 security csr del Server-Cert

Renew a certificate using the existing NSS private key

After the CA signs the CSR, confirm that the signed certificate contains the same public key before you import it. Hash the public key from the CSR:

bash
openssl req -in /etc/dirsrv/slapd-ldap1/Server-Cert.csr -noout -pubkey | sha256sum

Hash the public key from the signed certificate and compare the two lines:

bash
openssl x509 -in /root/ldap1-renewed.crt -noout -pubkey | sha256sum

The hashes must match.

Import the CA chain before the leaf certificate. Start with the root and set intentional trust:

bash
dsconf ldap1 security ca-certificate add --file /root/example-root-ca.crt --name "Example-Root-CA"

Mark the root as trusted to issue server certificates:

bash
dsconf ldap1 security ca-certificate set-trust-flags "Example-Root-CA" --flags "C,,"

Sample output:

output
Successfully edited certificate trust flags

Import intermediate CA certificates as required, then import the signed leaf certificate once under a new nickname so the current Server-Cert keeps working until you test the replacement:

bash
dsconf ldap1 security certificate add --file /root/ldap1-renewed.crt --name "ldap1-2027"

Sample output:

output
Successfully added certificate

Confirm the private key is linked:

bash
dsconf ldap1 security key list

When the new nickname shows State: NSS Certificate DB:ldap1-2027 instead of (orphan), the import matched the CSR key.

Sample output:

output
Key Id: ff29368fc2b47c682243b6decc4ed5b1786cb704
State: NSS Certificate DB:ldap1-2027

The signed certificate must be issued from the same CSR public key. certutil -S in the host SSCA database creates a new key and does not satisfy this check.

Switch the active nickname:

bash
dsconf ldap1 security rsa set --nss-cert-name "ldap1-2027"

Sample output:

output
Successfully updated security configuration (nsSSLToken)

Alternative to the preceding staged import and rsa set commands: when the nickname has not already been imported, add and activate it in one operation:

bash
dsconf ldap1 security certificate add --file /root/ldap1-renewed.crt --name "ldap1-2027" --primary-cert

Choose either the staged workflow or this one-step workflow. Do not run certificate add --primary-cert after ldap1-2027 already exists.

Keep the previous Server-Cert nickname in the NSS database until LDAPS, STARTTLS, replication, and application clients succeed with the new material.

WARNING
If you import a signed certificate that does not match the CSR private key, the nickname appears in dsconf security certificate list but dsconf security key list still shows only (orphan) keys. LDAPS fails when you point nsSSLPersonalitySSL at that nickname. Always confirm key linkage before you switch the active certificate.

Replace a certificate and private key created externally

When the CSR and private key were created outside Directory Server, such as through Let's Encrypt, a corporate HSM workflow, or openssl req -newkey, import the PEM pair together while the instance is stopped. Stop ldap2 so the import does not race with a running server:

bash
dsctl ldap2 stop

Import the external certificate and private key into the instance NSS database:

bash
dsctl ldap2 tls import-server-key-cert /root/ldap2-external.crt /root/ldap2-external.key

Start the instance again so Directory Server reloads the updated NSS material:

bash
dsctl ldap2 start

dsctl edits the local NSS store directly. Direct NSS changes made by another process are not synchronized reliably with the running server, so stop the instance before import and start it afterward.

Confirm the new active certificate:

bash
dsctl ldap2 tls show-server-cert

Sample output:

output
Issuer: "CN=ldap2.example.com"
        Subject: "CN=ldap2.example.com"
            DNS name: "ldap2.example.com"

By default, dsctl tls import-server-key-cert targets the Server-Cert nickname. Current builds may support --nickname; check dsctl INSTANCE tls import-server-key-cert --help. Do not pass a chain bundle to this command. Import the leaf certificate and key first, then add CA certificates separately with dsconf.


Import and update the CA certificate chain

Import a CA or intermediate that signs server certificates:

bash
dsconf ldap1 security ca-certificate add --file /root/example-ca.crt --name "Example-CA"

Mark the CA as trusted to issue server certificates:

bash
dsconf ldap1 security ca-certificate set-trust-flags "Example-CA" --flags "C,,"

Sample output:

output
Successfully edited certificate trust flags

Add T to the flags only when the CA also issues client certificates for TLS EXTERNAL binds (CT,,).

Import an intermediate CA and assign c,, so NSS recognizes it as a valid CA without making it an explicit trust anchor:

bash
dsconf ldap1 security ca-certificate add \
  --file /root/example-intermediate-ca.crt \
  --name "Example-Intermediate-CA"

Apply the intermediate trust flags:

bash
dsconf ldap1 security ca-certificate set-trust-flags "Example-Intermediate-CA" --flags "c,,"

The root and required intermediate CA certificates must be available to Directory Server so NSS can build the server certificate chain. Clients normally trust the root or another intended trust anchor. Required intermediate certificates must either be sent by the server during the handshake or be available in the client certificate store; they should not automatically be configured as client trust anchors. A dsconf NSS import does not necessarily update the convenience PEM file /etc/dirsrv/slapd-ldap1/ca.crt. Export the trusted CA nickname or maintain a known client bundle:

bash
dsctl ldap1 tls export-cert "Self-Signed-CA" --output-file /root/example-root-ca.pem

Select the active server certificate

After the renewal workflow imports ldap1-2027 and links it to the CSR private key, switch the active nickname to that certificate. The active server certificate is nsSSLPersonalitySSL under cn=RSA,cn=encryption,cn=config. List available server nicknames:

bash
dsconf ldap1 security certificate list

Before you switch nicknames, confirm:

  • The nickname exists in the NSS database
  • dsconf ldap1 security key list links a private key to that nickname
  • The certificate includes the LDAP hostname in SAN
  • The certificate is valid for server authentication

Switch the active nickname:

bash
dsconf ldap1 security rsa set --nss-cert-name "ldap1-2027"

Verify the active nickname:

bash
dsconf ldap1 security rsa get

Sample output:

output
nssslactivation: on
nssslpersonalityssl: ldap1-2027
nsssltoken: internal (software)

Keep the old Server-Cert nickname until the new one passes LDAPS and STARTTLS tests.


Reload or restart Directory Server

Listener changes require an instance restart. That includes first enabling nsslapd-security, changing the secure port, or disabling the plain-text port, as described in the TLS chapter.

Certificate replacement through dsconf is different. RHDS 13.2 on RHEL 10.2 documents online TLS certificate refresh for packages that provide dsconf INSTANCE config refresh-certs. Upstream 389 DS completed the corresponding CLI work across the 3.2.0 and 3.2.1 development cycle. Therefore, test for the command instead of relying only on the displayed 389 DS version.

Check whether your build exposes online refresh:

bash
dsconf ldap1 config --help

Sample output on the tested Rocky Linux 10.2 package:

output
usage: dsconf [-v] [-j] instance config [-h] {get,add,replace,delete} ...

When refresh-certs appears in that help output, switch the active nickname and refresh TLS material online without restarting:

bash
dsconf ldap1 security rsa set --nss-cert-name "ldap1-2027"

Reload the in-memory certificate store for new TLS connections:

bash
dsconf ldap1 config refresh-certs

The refreshed material is used for new TLS connections; existing connections are not explicitly closed, although a changed CA can cause some clients to disconnect.

When refresh-certs is not available, set the active nickname and restart the instance so the listener loads the new certificate:

bash
dsconf ldap1 security rsa set --nss-cert-name "ldap1-2027"

Restart ldap1 to pick up the NSS change:

bash
dsctl ldap1 restart
IMPORTANT
Direct modifications with certutil, pk12util, or offline dsctl tls commands edit NSS files on disk and do not synchronize the server's in-memory NSS state. Restart the instance after those changes.

After the instance is running, test both encrypted paths. Point LDAP clients at a current CA bundle you exported from NSS:

bash
export LDAPTLS_CACERT=/root/example-ca-chain.pem

Test LDAPS on port 636:

bash
ldapsearch -x -H ldaps://ldap1.example.com:636 -b "" -s base "(objectClass=*)" namingContexts

Test STARTTLS:

bash
ldapsearch -x -ZZ -H ldap://ldap1.example.com:389 -b "" -s base "(objectClass=*)" namingContexts

Both searches should return the root DSE including namingContexts.


Verify the renewed certificate

Inspect the leaf certificate the listener presents:

bash
openssl s_client -connect ldap1.example.com:636 -servername ldap1.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -serial -ext subjectAltName

Validate the complete chain:

bash
openssl s_client -connect ldap1.example.com:636 -servername ldap1.example.com -showcerts -verify_return_error -CAfile /root/example-ca-chain.pem </dev/null

Sample output near the end:

output
Verify return code: 0 (ok)

Verify STARTTLS directly:

bash
openssl s_client -starttls ldap -connect ldap1.example.com:389 -servername ldap1.example.com -verify_return_error -CAfile /root/example-ca-chain.pem </dev/null

Sample output near the end:

output
Verify return code: 0 (ok)

Compare with Directory Server's view:

bash
dsctl ldap1 tls show-server-cert

Open a new client connection after refresh-certs or the instance restart and confirm the serial number matches the renewed certificate. Also exercise:

  • A normal LDAP user bind over LDAPS or STARTTLS
  • Replication or chaining TLS settings if they pin certificates
  • Monitoring probes and application LDAP clients that cache connections

Manage the NSS database password

dscreate stores the NSS password in two files for different purposes:

File Purpose
pwdfile.txt Supplies the NSS database password to administrative tools
pin.txt Supplies the token name and NSS password when Directory Server starts

Both files live in the instance configuration directory:

text
/etc/dirsrv/slapd-ldap1/pwdfile.txt
/etc/dirsrv/slapd-ldap1/pin.txt

pin.txt uses the token-and-password format:

text
Internal (Software) Token:NEW_NSS_PASSWORD

Confirm that ownership, permissions, and SELinux types match a healthy instance created by the same 389 DS package. Do not recursively force one owner and group across the instance directory.

Change the NSS database password with certutil:

bash
certutil -W -d /etc/dirsrv/slapd-ldap1 -f /etc/dirsrv/slapd-ldap1/pwdfile.txt

certutil prompts for the old and new passwords interactively. It changes the NSS database password; it does not rewrite pwdfile.txt or pin.txt automatically.

After a successful password change:

  1. Put the new password alone in pwdfile.txt.
  2. Update pin.txt using Internal (Software) Token:NEW_NSS_PASSWORD.
  3. Preserve the existing ownership and mode of both files.
  4. Update secret-management or automation references.
  5. Restart the instance and verify that all NSS operations and TLS still work.

RHDS explicitly requires updating pin.txt when the NSS password changes.


Remove obsolete certificates safely

Before you delete a certificate:

  1. Confirm it is not the active nickname (dsconf ldap1 security rsa get).
  2. Confirm replication agreements, chaining, or client-auth settings do not reference it.
  3. Export a PKCS#12 backup when the private key might still be needed.
  4. Delete by exact nickname.
  5. Retest server startup and TLS.

Remove a server certificate nickname:

bash
dsconf ldap1 security certificate del Server-Cert

Sample output:

output
Successfully deleted certificate

Only remove the obsolete nickname after confirming the new certificate is active:

bash
dsconf ldap1 security rsa get

That command should return nssslpersonalityssl: ldap1-2027 before you delete Server-Cert.

Or with dsctl while the instance is stopped. Stop the instance before offline NSS edits:

bash
dsctl ldap1 stop

Remove the obsolete nickname from the NSS database:

bash
dsctl ldap1 tls remove-cert Server-Cert

Start the instance again so it reloads the trimmed certificate store:

bash
dsctl ldap1 start

Do not remove an issuing CA until every active server certificate has moved to a chain that no longer depends on it.


Recover from an expired certificate

Directory Server still starts

Import the renewed or replacement certificate, link it to the correct private key, set the active nickname, run dsconf config refresh-certs or restart according to your version, then verify LDAPS and STARTTLS from localhost before you reopen remote access.

Directory Server cannot provide LDAP TLS

Work locally on the host while the instance is stopped:

  • Use dsctl and certutil against /etc/dirsrv/slapd-ldap1/
  • Restore the configuration directory from your latest backup when the NSS database is corrupt
  • Import a PKCS#12 bundle into a temporary NSS directory first when you want to validate contents before merging
  • Confirm pwdfile.txt and pin.txt still unlock key4.db
  • Set nsSSLPersonalitySSL back to a nickname that has both certificate and private key

While the instance is stopped, validate the NSS contents locally. Display the active nickname certificate:

bash
certutil -L -d /etc/dirsrv/slapd-ldap1 -n "ldap1-2027"

List private keys in the NSS database:

bash
certutil -K -d /etc/dirsrv/slapd-ldap1 -f /etc/dirsrv/slapd-ldap1/pwdfile.txt

Start the instance only after those offline checks succeed:

bash
dsctl ldap1 start

Then test the listener:

bash
openssl s_client -connect localhost:636 -servername ldap1.example.com -CAfile /root/example-ca-chain.pem -verify_return_error </dev/null

Restore certificates from backup

You can restore from:

  • A dsconf backup create or dsctl db2bak archive (remember that config_files/ is not restored automatically with the database)
  • A supplemental tar archive of /etc/dirsrv/slapd-INSTANCE/
  • A password-protected PKCS#12 export

Restore NSS files from config_files/

An RHDS backup stores NSS material under config_files/ in the backup directory. Set the backup path you verified earlier:

bash
BACKUP_DIR="/var/lib/dirsrv/slapd-ldap1/bak/ldap1-BACKUP/config_files"

Stop the instance before replacing NSS files on disk:

bash
dsctl ldap1 stop

Preserve the current files first so you can roll back if the restore fails:

bash
mkdir -p /root/ldap1-current-nss
cp -a \
  /etc/dirsrv/slapd-ldap1/cert9.db \
  /etc/dirsrv/slapd-ldap1/key4.db \
  /etc/dirsrv/slapd-ldap1/pin.txt \
  /etc/dirsrv/slapd-ldap1/pwdfile.txt \
  /root/ldap1-current-nss/

Copy the backed-up NSS material into the live instance configuration directory:

bash
cp -a \
  "$BACKUP_DIR/cert9.db" \
  "$BACKUP_DIR/key4.db" \
  "$BACKUP_DIR/pin.txt" \
  "$BACKUP_DIR/pwdfile.txt" \
  /etc/dirsrv/slapd-ldap1/

I'll restore SELinux file contexts on the replaced NSS files with restorecon; see Ansible SELinux file contexts for how labels are applied after copies or restores:

bash
restorecon -Rv /etc/dirsrv/slapd-ldap1

RHDS backs up configuration and certificate files together but requires administrators to restore selected files manually. This workflow restores NSS material only; it does not restore dse.ldif. The configured certificate nickname and the certificate present in NSS therefore need to remain consistent.

Before you start the instance, confirm that nsSSLPersonalitySSL matches a nickname in the restored NSS database. Read the configured active nickname from dse.ldif:

bash
grep -i 'nssslpersonalityssl' /etc/dirsrv/slapd-ldap1/dse.ldif

List the certificate nicknames present in the restored NSS database:

bash
certutil -L -d /etc/dirsrv/slapd-ldap1

Confirm that the nickname in nsSSLPersonalitySSL exists in the restored NSS database and has a matching private key. If it does not, either restore the matching dse.ldif from the same backup or, while the instance remains stopped, update nsSSLPersonalitySSL to a certificate nickname present in the restored database. Restoring the complete dse.ldif also rolls back unrelated instance configuration, so use it only when that full configuration rollback is intended.

List private keys in the restored database using the NSS password file:

bash
certutil -K -d /etc/dirsrv/slapd-ldap1 -f /etc/dirsrv/slapd-ldap1/pwdfile.txt

Only start the instance after the certificate nickname and private key are both present:

bash
dsctl ldap1 start

Restore from a tar archive

For a configuration-directory restore, stop the instance, move the current directory aside, and extract the archive with ACLs, extended attributes, and SELinux labels preserved. Stop ldap1 before replacing its configuration directory:

bash
dsctl ldap1 stop

Move the broken configuration aside so you can extract the archive cleanly:

bash
mv /etc/dirsrv/slapd-ldap1 /etc/dirsrv/slapd-ldap1.broken.$(date +%F)

Extract the stopped-instance archive back into /etc/dirsrv:

bash
tar --acls --xattrs --selinux -xzpf /root/slapd-ldap1-config-2026-07-16-0742.tar.gz -C /etc/dirsrv

I'll run restorecon on the extracted configuration tree so file labels match policy:

bash
restorecon -Rv /etc/dirsrv/slapd-ldap1

Start the instance after the extract completes:

bash
dsctl ldap1 start

Verify sensitive files individually rather than applying a blanket chown. Check ownership with the chown command, file mode, and SELinux type on the NSS password files and databases:

bash
ls -lZ \
  /etc/dirsrv/slapd-ldap1/cert9.db \
  /etc/dirsrv/slapd-ldap1/key4.db \
  /etc/dirsrv/slapd-ldap1/pin.txt \
  /etc/dirsrv/slapd-ldap1/pwdfile.txt

Confirm that ownership, permissions, and SELinux types match a healthy instance created by the same 389 DS package. Do not recursively force one owner and group across the instance directory.

Output from this tested Rocky Linux package; other packages can differ:

output
-rw-------. 1 dirsrv dirsrv unconfined_u:object_r:dirsrv_config_t:s0 ... cert9.db
-rw-------. 1 dirsrv dirsrv unconfined_u:object_r:dirsrv_config_t:s0 ... key4.db
-rw-------. 1 dirsrv dirsrv unconfined_u:object_r:dirsrv_config_t:s0 ... pin.txt
-rw-------. 1 dirsrv dirsrv unconfined_u:object_r:dirsrv_config_t:s0 ... pwdfile.txt

Then verify the active nickname and TLS listener. Confirm which certificate nickname Directory Server will use:

bash
dsconf ldap1 security rsa get

Validate the live LDAPS listener against your client CA bundle:

bash
openssl s_client -connect ldap1.example.com:636 -servername ldap1.example.com -verify_return_error -CAfile /root/example-ca-chain.pem </dev/null

The backup must belong to the same instance configuration unless you are following a documented migration procedure.

Do not overwrite a working NSS database without keeping a copy of the current directory.

Import a PKCS#12 bundle offline. pk12util modifies NSS files directly, so stop the instance first:

bash
dsctl ldap1 stop

pk12util -i imports into the existing NSS database rather than replacing the complete database. Inspect the bundle and current nicknames first. An existing certificate with the same nickname can cause an import conflict, and PKCS#12 import does not restore nsSSLPersonalitySSL automatically.

List the PKCS#12 contents before you import:

bash
pk12util -l /root/ldap1-server-cert-backup.p12 -w /root/pk12-export.pw

List current NSS nicknames so you can spot nickname conflicts:

bash
certutil -L -d /etc/dirsrv/slapd-ldap1

Import the PKCS#12 bundle into the instance NSS database:

bash
pk12util -i /root/ldap1-server-cert-backup.p12 -d /etc/dirsrv/slapd-ldap1 -w /root/pk12-export.pw -k /etc/dirsrv/slapd-ldap1/pwdfile.txt

Before you start the instance, confirm that nsSSLPersonalitySSL matches a nickname in the NSS database and that the nickname has a matching private key. Read the configured active nickname:

bash
grep -i 'nssslpersonalityssl' /etc/dirsrv/slapd-ldap1/dse.ldif

List restored certificate nicknames:

bash
certutil -L -d /etc/dirsrv/slapd-ldap1

Confirm a private key is linked to the active nickname:

bash
certutil -K -d /etc/dirsrv/slapd-ldap1 -f /etc/dirsrv/slapd-ldap1/pwdfile.txt

Only start the instance after the certificate nickname and private key are both present:

bash
dsctl ldap1 start

Verify nickname, trust flags, and dsconf ldap1 security rsa get before you expose the listener. config refresh-certs does not make a direct pk12util import safe online. The online-refresh design expects dsconf for changes made while the server is running.


Certificate renewal with attribute encryption

IMPORTANT
Attribute encryption uses keys protected by the Directory Server TLS certificate. Replacing that certificate without the documented export and reimport workflow can make encrypted attributes unreadable and prevent the server from starting.

Follow the complete procedure in 389 Directory Server attribute encryption and the upstream section on updating TLS certificates used for attribute encryption before you change Server-Cert on an encrypted backend.


Monitor certificates before they expire

Track at least:

Field Example source
Nickname dsconf ldap1 security rsa get
Subject and SAN dsctl ldap1 tls show-server-cert
Issuing CA dsconf ldap1 security certificate get "ldap1-2027" or the nickname returned by rsa get
Expiration openssl x509 -checkend on live listener output
Renewal owner Change-management ticket
Backup location dsconf backup create archive and PKCS#12 path

Test whether the certificate expires within 30 days. That pattern suits cron, systemd timers, or Nagios-compatible checks.

bash
if ! openssl s_client -connect ldap1.example.com:636 -servername ldap1.example.com </dev/null 2>/dev/null | openssl x509 -checkend $((30 * 86400)) -noout; then echo "WARNING: ldap1 certificate expires within 30 days or could not be read"; exit 1; fi

When the certificate is healthy, openssl x509 -checkend prints:

output
Certificate will not expire

When the certificate is inside the window or unreadable, the script prints:

output
Certificate will expire
WARNING: ldap1 certificate expires within 30 days or could not be read

The exit status is non-zero when renewal action is required.


Troubleshoot certificate-management problems

Symptom Likely cause Fix
Certificate imports but no private key is available Signed cert does not match the CSR generated in NSS Reissue from the same CSR public key; confirm with dsconf security key list
Private key does not match the certificate Mixed PEM files from different CSRs or external keys Import the matching pair with dsctl tls import-server-key-cert; restart afterward
import-server-cert fails with SEC_ERROR_ADDING_CERT Server-Cert nickname already exists Use --nickname on current builds, or import online with dsconf security certificate add --name NEW_NICKNAME
Server presents the old certificate Wrong active nickname, long-lived connections, or missing refresh-certs Check dsconf security rsa get; run dsconf config refresh-certs or restart
Certificate chain is incomplete Missing intermediate CA in NSS Import the missing intermediate and normally assign c,,; place C,, on the intended server-certificate trust anchor and add T only for client-authentication issuers
NSS password rejected Wrong pwdfile.txt or pin.txt, permissions, or instance path Confirm -d /etc/dirsrv/slapd-INSTANCE; update both password files after certutil -W
Instance fails after NSS restore Ownership, SELinux context, or password mismatch Use tar --selinux and restorecon; verify individual file labels; confirm pwdfile.txt and pin.txt
LDAPS works but applications fail Client trust store, SAN mismatch, or cached connections Distribute exported CA PEM; align hostname with SAN; restart application pools
LDAPS fails after nickname switch New nickname has no linked private key Restore previous nickname; import cert that matches CSR key before retry
refresh-certs not found Package reports 389 DS 3.2.0 but lacks the CLI subcommand Run dsconf INSTANCE config --help; restart the instance after certificate changes when refresh-certs is absent

What's Next


References


Summary

  1. Inventory server and CA certificates, trust flags, and private-key linkage with dsconf and dsctl.
  2. Back up with dsconf backup create and verify config_files/ contains cert9.db, key4.db, pin.txt, and pwdfile.txt; supplement with PKCS#12 and stopped-instance tar archives.
  3. Generate a CSR before expiry and verify SAN coverage before CA submission.
  4. Import the CA chain, then the signed leaf; confirm the private key is no longer (orphan).
  5. Set the active nickname with dsconf security rsa set --nss-cert-name, then run dsconf config refresh-certs when available or restart for offline dsctl changes.
  6. Verify LDAPS, STARTTLS, and chain validation with openssl s_client -verify_return_error.
  7. Preserve recovery material, update both pwdfile.txt and pin.txt after NSS password changes, handle attribute encryption separately, and delete obsolete nicknames only after validation.

Frequently Asked Questions

1. Does a normal Directory Server database backup include TLS certificates?

Current RHDS 13 backups created by dsconf backup create or dsctl db2bak include the instance configuration, NSS certificate database, and custom schema under the backup config_files/ directory. However, these configuration files are not restored automatically. Keep an additional off-host PKCS#12 export and verify that every backup contains cert9.db, key4.db, and the required configuration files.

2. Can I renew a 389 Directory Server certificate without restarting the instance?

RHDS 13.2 on RHEL 10.2 documents online certificate activation with dsconf INSTANCE config refresh-certs. Do not assume that every package reporting 389 DS 3.2.0 contains the matching CLI support. Check dsconf INSTANCE config --help on the installed build. On the tested Rocky Linux 10.2 package, 389-ds-base-3.2.0-8.el10_2, refresh-certs is unavailable, so a restart is required after certificate or active-nickname changes.

3. What happens if I replace the TLS certificate when attribute encryption is enabled?

Attribute-encryption keys are wrapped with the server TLS certificate. Replacing that certificate without the documented export and reimport workflow can make encrypted attributes unreadable. Follow the attribute-encryption chapter before you change Server-Cert in that configuration.

4. Why does dsctl tls import-server-cert fail with SEC_ERROR_ADDING_CERT?

By default, dsctl tls import-server-cert uses the Server-Cert nickname. If that nickname already exists, some versions or import paths return SEC_ERROR_ADDING_CERT. On current builds, use --nickname for a new nickname, or import online with dsconf security certificate add --name NEW_NICKNAME. Check the installed command --help, because nickname and replacement behavior differs across releases. Changes made directly through dsctl tls require a restart before the running server uses them.

5. Where is the NSS database password stored?

dscreate stores the NSS password in two files for different purposes. Administrative tools use pwdfile.txt, while Directory Server uses pin.txt to unlock the internal software token during startup. After changing the NSS password with certutil -W, update both files where present, preserve their package-created ownership and permissions, and store the password in an approved secret manager.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …