Skip to content

LDAPS Certificate Trust in Docker Deployments

Trusting an Internal CA for LDAPS in Docker Deployments

Section titled “Trusting an Internal CA for LDAPS in Docker Deployments”

Active Directory and most internal directory servers present a certificate issued by a private CA. The rConfig V8 Pro container does not trust that CA out of the box, so LDAPS binds fail until you add it. This page shows how to mount the CA certificate into the container so the trust survives docker compose restart, docker compose down, and image upgrades.

Use this guide if you connect rConfig to LDAP over LDAPS (port 636) or StartTLS (port 389) and see one of these:

  • Test Connection on Settings → LDAP Setup fails, with Can't contact LDAP server in the response, while the same host and credentials work from another machine.
  • The bind starts working after you run update-ca-certificates inside the container by hand, then fails again after the container is restarted or updated.

If your directory server uses a certificate from a public CA (DigiCert, Sectigo, Let’s Encrypt), the container already trusts it and you do not need this page. If the bind succeeds but login fails with Could not find user in LDAP directory, that is a search problem rather than a certificate problem: check the Base DN and LDAP Login Attribute on the LDAP integration page.

Why manual certificate installation does not persist

Section titled “Why manual certificate installation does not persist”

Anything you install with docker exec lands in the container’s writable layer, which is discarded when the container is recreated. Pulling a new rConfig image, editing docker-compose.yml, or running docker compose down all recreate the container and take the certificate with them.

The fix is to keep the certificate on the container host and bind mount it in, the same approach used for encrypted database connections.

PHP’s LDAP extension is a wrapper around OpenLDAP’s client library, so it reads its trust settings from /etc/ldap/ldap.conf and from the LDAPTLS_* environment variables, not from rConfig’s own configuration. There is no CA certificate field in the rConfig LDAP settings form, and setting a certificate path in .env has no effect on LDAP trust.

  1. Export the CA certificate from your PKI. On a Windows CA this is usually available from Certification Authority → Properties → View Certificate → Details → Copy to File, or with certutil -ca.cert ca.cer.

  2. Confirm it is PEM encoded. A PEM file starts with -----BEGIN CERTIFICATE----- in a text editor. Windows commonly exports DER, which OpenLDAP cannot read, so convert it:

    Terminal window
    openssl x509 -inform der -in ca.cer -out ad-ca.crt
  3. If your directory certificate was issued by a subordinate (issuing) CA, concatenate the full chain into a single file, issuing CA first, root CA last:

    Terminal window
    cat issuing-ca.crt root-ca.crt > ad-ca.crt
  4. Place the file on the container host next to your docker-compose.yml, for example /home/rconfig/certs/ad-ca.crt, and make it world readable. The CA certificate is public information, so no restrictive permissions are needed:

    Terminal window
    chmod 644 /home/rconfig/certs/ad-ca.crt

Create /home/rconfig/certs/ldap.conf on the container host with two lines:

TLS_CACERT /certs/ad-ca.crt
TLS_REQCERT hard

The path in TLS_CACERT is the path inside the container, set by the volume mount in the next step, not the host path.

TLS_REQCERT hard makes rConfig refuse to bind if the certificate cannot be validated, which is what you want in production. See the gotchas below before reaching for never.

Add two read-only bind mounts and two environment variables to the app service in your docker-compose.yml, alongside the existing entries:

services:
app:
environment:
# ... existing environment entries, unchanged ...
- LDAPTLS_CACERT=/certs/ad-ca.crt
- LDAPTLS_REQCERT=hard
volumes:
# ... existing rConfig volume mappings, unchanged ...
- /home/rconfig/certs/ad-ca.crt:/certs/ad-ca.crt:ro
- /home/rconfig/certs/ldap.conf:/etc/ldap/ldap.conf:ro

The mounted ldap.conf is what does the work. The two environment variables cover the same ground for any process that starts with a different configuration file, and cost nothing to set.

Recreate the container so the new mounts and variables take effect:

Terminal window
docker compose up -d

On SELinux hosts (Rocky, RHEL, Fedora), append :z to both mounts, for example - /home/rconfig/certs/ad-ca.crt:/certs/ad-ca.crt:ro,z.

Go to Settings → LDAP Setup and click Test Connection. A successful test confirms that the container validated the directory certificate and completed the bind with your service account.

Every step of the exchange is written to the activity log. Open Logs → Activity and filter on authentication events to see the bind result and, on a successful user lookup, a line reading Attempting to login using distinguished name: CN=....