Initialization Scripts
Run custom scripts on the first container startup to automate setup tasks like loading data, creating organizational units, or applying custom configurations.How It Works
When the container starts for the first time (empty database), it executes any files in/docker-entrypoint-initdb.d/:
-
Shell scripts (
.sh) — executed with bash -
LDIF files (
.ldif) — applied via ldapadd/ldapmodify - Executable files — run directly
Important: Scripts only run on first startup. On restart, the container detects existing data and skips initialization.
Quick Start
Create an init script to load sample data:
mkdir -p init
cat > init/01-load-data.sh << 'EOF'
#!/bin/bash
set -e
echo "Loading sample data..."
ldapadd -x -D "cn=Manager,dc=example,dc=com" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Departments
dn: ou=Engineering,ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Engineering
dn: uid=john.doe,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
uid: john.doe
cn: John Doe
sn: Doe
givenName: John
mail: john.doe@example.com
userPassword: {SSHA}encryptedpassword
LDIF
echo "Sample data loaded successfully!"
EOF
chmod +x init/01-load-data.sh
Mount and run:
services:
openldap:
image: ghcr.io/vibhuvioio/openldap:latest
environment:
- LDAP_DOMAIN=example.com
- LDAP_ADMIN_PASSWORD=changeme
volumes:
- ./init:/docker-entrypoint-initdb.d:ro
docker compose up -d
# Watch the initialization
docker logs -f openldap
Common Use Cases
1. Load Sample Data
Create init/01-data.sh:
#!/bin/bash
set -e
echo "Creating organizational structure..."
ldapadd -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Departments
dn: ou=Engineering,ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Engineering
dn: ou=Sales,ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Sales
LDIF
echo "Creating test users..."
for i in {1..5}; do
ldapadd -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: uid=user$i,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
uid: user$i
cn: Test User $i
sn: User
mail: user$i@example.com
userPassword: password$i
LDIF
done
2. Apply Custom Schema
Create init/02-schema.ldif:
dn: cn=myapp,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: myapp
olcAttributeTypes: ( 1.3.6.1.4.1.99999.1.1
NAME 'appRole'
DESC 'Application role'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} )
olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1
NAME 'appUser'
DESC 'Application user'
SUP inetOrgPerson
STRUCTURAL
MAY ( appRole ) )
Apply with a wrapper script init/02-schema.sh:
#!/bin/bash
set -e
echo "Loading custom schema..."
ldapadd -Y EXTERNAL -H ldapi:/// -f /docker-entrypoint-initdb.d/02-schema.ldif
echo "Creating app users..."
ldapadd -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: ou=AppUsers,dc=example,dc=com
objectClass: organizationalUnit
ou: AppUsers
dn: uid=appadmin,ou=AppUsers,dc=example,dc=com
objectClass: appUser
uid: appadmin
cn: App Admin
sn: Admin
appRole: administrator
userPassword: adminpass
LDIF
3. Increase Database Size
Create init/00-database-config.sh:
#!/bin/bash
set -e
echo "Configuring database size..."
ldapmodify -Y EXTERNAL -H ldapi:/// <<LDIF
dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcDbMaxSize
olcDbMaxSize: 2147483648
LDIF
echo "Database size set to 2GB"
Run this as 00-*.sh to ensure it executes before data loading.
4. Create Groups with Members
Create init/03-groups.sh:
#!/bin/bash
set -e
echo "Creating groups..."
ldapadd -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: cn=admins,ou=Group,dc=example,dc=com
objectClass: groupOfNames
cn: admins
member: uid=john.doe,ou=People,dc=example,dc=com
dn: cn=developers,ou=Group,dc=example,dc=com
objectClass: groupOfNames
cn: developers
member: uid=jane.doe,ou=People,dc=example,dc=com
member: uid=bob.smith,ou=People,dc=example,dc=com
LDIF
Execution Order
Scripts execute in alphabetical order. Use numeric prefixes to control order:
init/
├── 00-database-config.sh # First: configure database
├── 01-schema.sh # Second: load custom schema
├── 02-ous.sh # Third: create OUs
└── 03-users.sh # Last: create users
Environment Variables Available
Scripts have access to these environment variables:
| Variable | Description | Example |
|---|---|---|
LDAP_ADMIN_DN | Full admin DN | cn=Manager,dc=example,dc=com |
LDAP_ADMIN_PASSWORD | Admin password | changeme |
LDAP_BASE_DN | Base DN | dc=example,dc=com |
LDAP_DOMAIN | Domain | example.com |
Error Handling
Scripts should use set -e to fail on errors:
#!/bin/bash
set -e # Exit immediately if a command fails
# Your commands here
If a script fails, the container logs the error but continues starting. Check logs:
docker logs openldap | grep -i error
Idempotency
Scripts may run if the database is wiped. Make them idempotent when possible:
#!/bin/bash
set -e
# Check if entry exists before creating
if ! ldapsearch -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" \
-b "ou=Departments,dc=example,dc=com" -s base 2>/dev/null | grep -q "ou:"; then
echo "Creating Departments OU..."
ldapadd -x -D "$LDAP_ADMIN_DN" -w "$LDAP_ADMIN_PASSWORD" <<LDIF
dn: ou=Departments,dc=example,dc=com
objectClass: organizationalUnit
ou: Departments
LDIF
else
echo "Departments OU already exists, skipping..."
fi
Download Example
openldap-init
Explorer
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
services: openldap: build: context: . dockerfile: Dockerfile container_name: openldap environment: # Required - LDAP_DOMAIN=example.com - LDAP_ADMIN_PASSWORD=changeme-strong-password # Optional (defaults shown) # - LDAP_ORGANIZATION=Example Organization # - LDAP_CONFIG_PASSWORD=config # - ENABLE_REPLICATION=false # - ENABLE_MONITORING=true # - ENABLE_MEMBEROF=false # - LDAP_LOG_LEVEL=stats stats2 ports: - "389:389" - "636:636" volumes: # Required: Persistent data - ldap-data:/var/lib/ldap - ldap-config:/etc/openldap/slapd.d # Required: Logs (even with read-only rootfs) - ldap-logs:/logs # Optional: Custom schemas # - ./custom-schema:/custom-schema:ro # Optional: Initialization scripts # - ./init-scripts:/docker-entrypoint-initdb.d:ro # Optional: TLS certificates # - ./certs:/certs:ro # Security: Read-only rootfs with tmpfs for temporary files read_only: true tmpfs: - /tmp - /var/run/openldap # Security: Drop all capabilities and add only required ones security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - NET_BIND_SERVICE - SETUID - SETGID - CHOWN # Grace period for clean shutdown stop_grace_period: 30s # Health check built into image healthcheck: test: ["CMD", "/usr/local/bin/scripts/healthcheck.sh", "basic"] interval: 30s timeout: 5s start_period: 30s retries: 3 restart: unless-stopped networks: - ldap-network # Resource limits for production stability deploy: resources: limits: memory: 512M cpus: '1.0' reservations: memory: 128M # Log rotation to prevent disk exhaustion logging: driver: json-file options: max-size: "10m" max-file: "3" volumes: ldap-data: ldap-config: ldap-logs: # Custom network for service isolation networks: ldap-network: driver: bridge
YAMLUTF-8
Ln 972 files
Connection Details
| Setting | Value |
|---|---|
| Host | localhost |
| LDAP Port | 389 |
| Bind DN | cn=Manager,dc=example,dc=com (or your custom) |
| Password | As configured in LDAP_ADMIN_PASSWORD |
Cleanup
# Stop and remove data (runs init scripts again on next start)
docker compose down -v
# Stop but keep data (skips init scripts on next start)
docker compose down
Troubleshooting
Scripts not running:-
Check container logs:
docker logs openldap | grep -i init -
Verify scripts are executable:
chmod +x init/.sh - Ensure database is empty (scripts only run on first startup)
- Container was restarted with existing data (expected behavior)
- Or script isn't idempotent and ran twice due to container recreation
-
Ensure scripts have execute permission:
chmod +x init/.sh - Check file ownership matches container user (UID 55)