Populating the directory from scratch: planning the domain and organizational unit structure, adding users with inetOrgPerson and posixAccount, creating groups with groupOfNames, and batch operations with ldapadd.

In episode 6 you mastered the client tools and the LDIF format. Now it's time to use them: episode 7 covers real directory population, from planning the directory tree structure, creating the domain entry and organizational units, adding users with ldapadd, creating groups, to importing many entries at once via batch operations.
Before adding your first entry, design the shape of the tree first. A tidy directory structure (DIT) determines how easy ACLs and searches will be in the following episodes. The basic principles:
dc=example,dc=com.ou= (organizational unit).A commonly used layout: dc=example,dc=com at the top, then ou=People for all users and ou=Groups for all groups. If the organization grows, you can add branches like ou=Contractors or ou=Departments without moving existing entries.
The base structure consists of a domain entry and two OUs. Save them in a single LDIF file:
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: Example Inc
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: GroupsImport with ldapadd:
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f struktur-dasar.ldifThe -f option reads the whole file at once; entries are separated by blank lines. After running it, check the result with ldapsearch -x -b dc=example,dc=com -s sub "(objectClass=*)" and make sure all three entries appear.
Note
The dc=example,dc=com entry must be created first because LDAP is hierarchical — a child entry cannot exist before its parent. The dpkg-reconfigure slapd configuration in episode 5 usually creates this domain entry during installation, so just make sure it's there.
A user is represented with a combination of object classes. The standard for enterprise directories:
inetOrgPerson — personal attributes like cn, sn, givenName, and mail.posixAccount — Unix attributes like uidNumber, gidNumber, homeDirectory, and loginShell.dn: uid=budi,ou=People,dc=example,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
uid: budi
cn: Budi Santoso
sn: Santoso
givenName: Budi
mail: budi@example.com
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/budi
loginShell: /bin/bash
userPassword: {SSHA}1K0vX...Required rules: inetOrgPerson requires cn and sn; posixAccount requires uid, uidNumber, gidNumber, and homeDirectory. The uidNumber and gidNumber values must be unique so they don't collide when used by the system.
Never fill the userPassword attribute with a raw password. Create a hash first with slappasswd:
slappasswd
New password:
Re-enter new password:
{SSHA}1K0vX...OpenLDAP 2.5 supports the salted hashes SSHA, SSHA256, SSHA512, as well as CRYPT and ARGON2 (if the module is built). The generated hash is then copied into userPassword in the LDIF. Full details on hashing are covered in episode 12.
Add the user with ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f budi.ldif.
Important
Always write userPassword as a hash from slappasswd, never as plain text. In real environments, plain text can easily be read by anyone with read access to this attribute.
Groups are split into two needs: groups for directory management and groups for Unix mapping.
groupOfNames — requires cn and at least one member, suitable for application groups.posixGroup — requires cn and gidNumber, uses memberUid for a Unix-style member list.The two object classes are often combined in one entry:
dn: cn=devel,ou=Groups,dc=example,dc=com
objectClass: groupOfNames
objectClass: posixGroup
cn: devel
gidNumber: 1001
member: uid=budi,ou=People,dc=example,dc=com
member: uid=sari,ou=People,dc=example,dc=com
memberUid: budi
memberUid: sariMembers are filled as full DNs in the member attribute. The memberOf attribute on the user side doesn't need to be filled manually — it's maintained automatically by the memberOf overlay you'll enable in episode 11.
Add it with ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f group-devel.ldif.
An LDIF file can hold many entries at once — separate them with blank lines, and each entry still starts with dn::
dn: uid=sari,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: sari
cn: Sari Wulandari
sn: Wulandari
uidNumber: 1002
gidNumber: 1001
homeDirectory: /home/sari
dn: uid=aji,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: aji
cn: Aji Pratama
sn: Pratama
uidNumber: 1003
gidNumber: 1001
homeDirectory: /home/ajiFor large volumes, the import can be called repeatedly from a script. Note two default behaviors: ldapadd stops on the first error, and its return code reflects success. Add -c to continue even when some entries fail:
ldapadd -c -x -D "cn=admin,dc=example,dc=com" -W -f semua-user.ldifLDAP doesn't guarantee full atomicity like a relational database: each entry is processed as a separate operation. If one file holds a hundred entries and entry 50 fails, entries 1 through 49 are still stored. That's why you should test files on a development server, and for changes that must be all-or-nothing, split them into small files verified in stages.
Episode 7 takes the directory from empty to populated: planning the domain and OU structure, creating user entries with inetOrgPerson plus posixAccount, groups with groupOfNames plus posixGroup, password hashing via slappasswd, and batch operations with -c mode.
Key takeaways:
inetOrgPerson needs cn and sn; posixAccount needs uid, uidNumber, gidNumber, homeDirectory.userPassword — always hash with slappasswd.In the next episode, episode 8, you'll modify and delete what you've built: adding, replacing, and removing attributes, renaming RDNs, moving entries, and safely deleting entries.