DEV Community

selfhosting.sh
selfhosting.sh

Posted on • Originally published at selfhosting.sh

Bookstack Ldap Issues

The Problem

BookStack LDAP login fails with one of these errors:

This information does not correspond to any account.
Enter fullscreen mode Exit fullscreen mode
ldap_bind(): Unable to bind to server: Can't contact LDAP server
Enter fullscreen mode Exit fullscreen mode

Or login silently fails — you enter correct LDAP credentials but BookStack rejects them without a useful error message.

The Cause

BookStack's LDAP integration has several configuration points that must all be correct for authentication to work. The most common causes:

  1. User filter placeholder syntax{user} vs ${user} confusion
  2. Docker Compose variable escaping — the $ in ${user} gets eaten by Docker's env interpolation
  3. TLS/SSL certificate validation — self-signed certs fail PHP's LDAP TLS check
  4. Wrong bind DN or base DN — the service account can't search or the search starts in the wrong place
  5. SELinux blocking — on RHEL/Rocky, SELinux silently blocks outbound LDAP connections

The Fix

Method 1: Fix the User Filter (Most Common)

The LDAP_USER_FILTER variable must contain the correct placeholder syntax.

In a .env file:

LDAP_USER_FILTER=(&(sAMAccountName=${user}))
Enter fullscreen mode Exit fullscreen mode

In docker-compose.yml environment section — use double $$ to escape Docker's variable interpolation:

environment:
  LDAP_USER_FILTER: "(&(sAMAccountName=$${user}))"
Enter fullscreen mode Exit fullscreen mode

Docker Compose treats $ as a variable reference. A single $ results in BookStack receiving a literal string without the placeholder, so the filter never matches any user.

Verify what BookStack actually sees:

docker exec bookstack printenv | grep LDAP_USER_FILTER
# Should show: LDAP_USER_FILTER=(&(sAMAccountName=${user}))
# NOT: LDAP_USER_FILTER=(&(sAMAccountName=))
Enter fullscreen mode Exit fullscreen mode

For OpenLDAP, use uid instead of sAMAccountName:

LDAP_USER_FILTER=(&(uid=${user}))
Enter fullscreen mode Exit fullscreen mode

Method 2: Fix TLS/SSL Certificate Issues

If you see Can't contact LDAP server when using LDAPS or StartTLS:

Option A: Use StartTLS instead of LDAPS (recommended):

LDAP_SERVER=ldap.example.com:389
LDAP_START_TLS=true
LDAP_TLS_INSECURE=false
Enter fullscreen mode Exit fullscreen mode

Option B: Skip certificate validation (testing only):

LDAP_SERVER=ldaps://ldap.example.com:636
LDAP_TLS_INSECURE=true
Enter fullscreen mode Exit fullscreen mode

Option C: Mount your CA certificate into the container:

volumes:
  - ./my-ca.crt:/usr/local/share/ca-certificates/my-ca.crt:ro
Enter fullscreen mode Exit fullscreen mode

Then rebuild the certificate store inside the container:

docker exec bookstack update-ca-certificates
docker compose restart bookstack
Enter fullscreen mode Exit fullscreen mode

Method 3: Fix Network Connectivity

Test that the BookStack container can reach your LDAP server:

# Test from inside the container
docker exec bookstack bash -c "apt-get update && apt-get install -y ldap-utils && \
  ldapsearch -x -H ldap://ldap.example.com:389 -b '' -s base objectclass=*"
Enter fullscreen mode Exit fullscreen mode

If this fails, check:

  • Firewall rules between the Docker network and your LDAP server
  • DNS resolution (use IP address in LDAP_SERVER to rule out DNS issues)
  • Correct port (389 for LDAP, 636 for LDAPS)

On RHEL/Rocky with SELinux:

# Check if SELinux is blocking
getenforce
# If "Enforcing", allow httpd to connect to LDAP:
sudo setsebool -P httpd_can_network_connect on
Enter fullscreen mode Exit fullscreen mode

Method 4: Verify Bind Credentials and Base DN

Test the service account credentials independently:

# Test bind with ldapsearch
ldapsearch -x -H ldap://ldap.example.com:389 \
  -D "cn=bookstack,cn=users,dc=example,dc=com" \
  -w "your-service-password" \
  -b "dc=example,dc=com" \
  "(sAMAccountName=testuser)"
Enter fullscreen mode Exit fullscreen mode

This should return the test user's attributes. If it returns nothing:

  • "Invalid credentials" → wrong LDAP_DN or LDAP_PASS
  • Empty result → wrong LDAP_BASE_DN or the service account lacks search permissions
  • "No such object" → the LDAP_BASE_DN doesn't exist in your directory

Common Active Directory base DNs:

# Users are typically in:
LDAP_BASE_DN=cn=Users,dc=example,dc=com
# Note the capital "U" — Active Directory uses "Users" not "users"
Enter fullscreen mode Exit fullscreen mode

Method 5: Enable Debug Logging

Turn on BookStack's debug mode to see detailed LDAP errors:

APP_DEBUG=true
LDAP_DUMP_USER_DETAILS=true
Enter fullscreen mode Exit fullscreen mode

Restart BookStack, attempt a login, and check the logs:

docker compose logs bookstack | grep -i ldap
Enter fullscreen mode Exit fullscreen mode

LDAP_DUMP_USER_DETAILS=true logs the attributes returned by LDAP for matched users — useful for verifying that email and display name attributes map correctly.

Disable debug mode after troubleshooting — it exposes sensitive information in error pages.

Complete Working Configuration

Variable OpenLDAP Example Active Directory Example
AUTH_METHOD ldap ldap
LDAP_SERVER ldap.example.com:389 dc01.corp.example.com:389
LDAP_BASE_DN dc=example,dc=com cn=Users,dc=corp,dc=example,dc=com
LDAP_DN cn=bookstack,ou=services,dc=example,dc=com cn=bookstack,cn=Users,dc=corp,dc=example,dc=com
LDAP_PASS service-password service-password
LDAP_USER_FILTER (&(uid=${user})) (&(sAMAccountName=${user}))
LDAP_ID_ATTRIBUTE uid objectGUID
LDAP_EMAIL_ATTRIBUTE mail mail
LDAP_DISPLAY_NAME_ATTRIBUTE cn displayName
LDAP_START_TLS true true
LDAP_USER_TO_GROUPS false false

Prevention

  • Always test LDAP connectivity with ldapsearch before configuring BookStack
  • Use double $$ for the user filter placeholder when setting it in docker-compose.yml
  • Start with LDAP_USER_TO_GROUPS=false — enable group sync only after basic login works
  • Keep APP_DEBUG=false in production
  • Document your LDAP_BASE_DN — it's the most frequently wrong setting

Related

Top comments (0)