Abstract : in some cases, it is interesting to have multiples instances of OpenLDAP running on the same machine. This could be used to separate data, test replication on the same server, or whatever you want.
This note will explain how to do this.
Main principles
In a standard GNU/Linux OpenLDAP install (Red Hat or Debian based), there are several files or directories used to set up OpenLDAP instance and data :
- /etc/openldap/slapd.d : this directory stores the configuration files for the instance.
- /var/lib/ldap : this directory contains the data for the instance
- /etc/init.d/slapd : this file is the start / stop script for the instance
- /etc/sysconfig/ldap : defines the default ports for LDAP, LDAPS (secured LDAP) and LDAPI (Interconnect = Unix Socket)
Whenever you start the instance, using :
/etc/init.d/slapd start
this will retrieve data from default setup (ie : /etc/sysconfig/ldap
and /etc/init.d/slapd.d
directory).
Then, you can see what is running with ps -ef command :
ps -ef ... ldap 17233 1 0 18:13 ? 00:00:00 /usr/sbin/slapd -h ldap:/// ldaps:/// ldapi:/// -u ldap ...
This is the default setup. If we look at the file /etc/sysconfig/ldap
, we see that it defines several variables :
# Options of slapd (see man slapd) #SLAPD_OPTIONS= # At least one of SLAPD_LDAP, SLAPD_LDAPI and SLAPD_LDAPS must be set to 'yes'! # # Run slapd with -h "... ldap:/// ..." # yes/no, default: yes SLAPD_LDAP=yes # Run slapd with -h "... ldapi:/// ..." # yes/no, default: yes SLAPD_LDAPI=yes # Run slapd with -h "... ldaps:/// ..." # yes/no, default: no SLAPD_LDAPS=yes # Run slapd with -h "... $SLAPD_URLS ..." # This option could be used instead of previous three ones, but: # - it doesn't overwrite settings of $SLAPD_LDAP, $SLAPD_LDAPS and $SLAPD_LDAPI options # - it isn't overwritten by settings of $SLAPD_LDAP, $SLAPD_LDAPS and $SLAPD_LDAPI options # example: SLAPD_URLS="ldapi:///var/lib/ldap_root/ldapi ldapi:/// ldaps:///" # default: empty SLAPD_URLS=
Then we can use the SLAPD_URLS variable to set ports for ldap, ldaps and so on.
Note : if you use this variable, you must not use the other one (SLAPD_LDAP, SLAPD_LDAPS), because the start script uses the full URL and also separate variables.
For example, with such a configuration file :
#SLAPD_LDAP=yes #SLAPD_LDAPI=yes #SLAPD_LDAPS=yes SLAPD_URLS="ldap://:1389/ ldapi:/// ldaps://:1636/"
If we start the slapd process with /etc/init.d/slapd start
, the result is :
ps -ef ldap 17176 1 0 18:11 ? 00:00:00 /usr/sbin/slapd -h ldap://:1389/ ldapi:/// ldaps://:1636/ -u ldap
We have been able to change the port. This gives a pretty good idea of what needs to be done to run multiple instances.
The man slapd
command reveals also some interesting options :
slapd [-4|-6] [-T {acl|a[dd]|auth|c[at]| d[n]|i[ndex]|p[asswd]|s[chema]|t[est]}] [-d debug-level] [-f slapd- config-file] [-F slapd-config-directory] [-h URLs] [-n service-name] [-s syslog-level] [-l syslog-local-user] [-o option[=value]] [-r directory] [-u user] [-g group] [-c cookie]
- -d debug-level : run slapd with -d -1 to have a "dump" of all that happens when slapd tries to run. This can reveal issues with permissions, malformed ldif / schema files, etc
- -F : slapd config directory, this means that you can use an alternative configuration. That is, separate instance !
- -h URLS : this is what appears on the ps -ef command. Here we will be able to set the listening ports
- -u / -g : user and group used to run slapd process. Interesting is you want to run separate instances with different users
How to implement multiple instances ?
If we want to have mutliple instances on the same server, we must define :
- a configuration directory, which will include database configuration, schema definition, etc
- data directory
- logs directory (optional)
- a startup script, which will define the ports and configuration directory
- run files, used during startup (in /var/run or /run)
Test case
Let's imagine a scenario where we will have 3 separate instances on the same server, which can be used to test replication in a master/master + slave configuration.
We will name those instances master1, master2 and slave1
In this scenario, we use several partitions to dispatch data on the server :
- /srv/data : will contain data for applications
- /srv/conf : will contain all configuration files
- /srv/logs : will contain transaction logs files
- /srv/bin : will contain programs and scripts
Configuration directory
I think that the best option is to make a copy of the initial slapd.d directory.
So, once openldap is installed, we will copy the configuration. We will name each directory with a suffix '.d', just to mimic slapd.d configuration name
yum install openldap openldap-servers openldap-clients # create the main configuration directory mkdir /srv/conf/openldap cp -R /etc/openldap/slapd.d /srv/conf/openldap/master1.d cp -R /etc/openldap/slapd.d /srv/conf/openldap/master2.d cp -R /etc/openldap/slapd.d /srv/conf/openldap/slave1.d
Let's check the content of /srv/conf/openldap/master1.d
directory :
ls -R /srv/conf/openldap/master1.d /srv/conf/openldap/master1.d: cn=config cn=config.ldif /srv/conf/openldap/master1.d/cn=config: cn=schema cn=schema.ldif olcDatabase={0}config.ldif olcDatabase={-1}frontend.ldif olcDatabase={1}monitor.ldif olcDatabase={2}bdb.ldif /srv/conf/openldap/master1.d/cn=config/cn=schema: cn={0}corba.ldif cn={11}collective.ldif cn={2}cosine.ldif cn={4}dyngroup.ldif cn={6}java.ldif cn={8}nis.ldif cn={10}ppolicy.ldif cn={1}core.ldif cn={3}duaconf.ldif cn={5}inetorgperson.ldif cn={7}misc.ldif cn={9}openldap.ldif
Note : in fact it will be more interesting to setup the first master configuration, which declares the root suffix, data and so on, and the duplicate this first directory.
Setup for each instance
Some configuration files include elements of structure. Therefore, these files must be updated to reflect the new setup.
cn=config.ldif
The file LDAP.D/cn=config.ldif
contains several references to directories.
These attributes should be changed accordingly (in this example, we update data for master1 instance):
- olcConfigDir: /etc/openldap/slapd.d => change to /srv/conf/openldap/master1.d
- olcArgsFile: /var/run/openldap/slapd.args => change to /var/run/openldap/master1.args
- olcPidFile: /var/run/openldap/slapd.pid => change to /var/run/openldap/master1.pid
olcDatabase
In your database definition file olcDatabase={2}bdb.ldif, change the data directory (olcDbDirectory attribute).
- olcDbDirectory: /var/lib/ldap => change to /srv/data/master1
Data directory
Here again, we will create one sub-directory for each instance.
mkdir -p /srv/data/openldap mkdir /srv/data/master1 mkdir /srv/data/master2 mkdir /srv/data/slave1
Logs directory
These directories contains the transaction log files, which are used by OpenLDAP.
In recent versions, OpenLDAP "technical" logging is using syslog mechanism.
Startup script
Then, you must create a startup script for each instance, which will start with the correct parameters.
A very simple script could use the configuration in code :
#!/bin/bash # # Startup script for master1 # SLAPD_URLS="ldap://:2389/ ldapi://var%2Frun%2Fopenldap%2Fldap-master1 ldaps://:2636/" SLAPD_CONFDIR=/srv/conf/openldap/master1.d SLAPD_NAME=master1 SLAPD_USER=ldap SLAPD_GROUP=ldap # echo "Starting ${SLAPD_NAME} instance..." /usr/sbin/slapd -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${SLAPD_CONFDIR} -n ${SLAPD_NAME}
Note : the URL for ldapi should be encoded as an URL, with '/' replaced by '%2F', as specified in the "man slapd" command.
In order to keep everything quite simple, we can add a file in the configuration directory, that will "emulate" the default /etc/sysconfig/ldap
file.
For example, let's create a file /srv/conf/openldap/master1.d/config.ldap
which contains :
SLAPD_URLS="ldap://:2389/ ldapi://var%2Frun%2Fopenldap%2Fldap-master1 ldaps://:2636/" SLAPD_SHUTDOWN_TIMEOUT=3 SLAPD_NAME=master1 SLAPD_USER=ldap SLAPD_GROUP=ldap
Then, our start script could be located in /srv/bin/openldap/slapd
. It will be run with these options :
/srv/bin/openldap/slapd [start|stop|status] <INSTANCE_NAME>
For example, to start the instance master1, we should run :
/srv/bin/openldap/slapd start master1
Our startup script should then test if the configuration file exists, and then source this file to define the parameters.
Then, this will run the command :
CONF_BASE=/srv/conf/openldap source ${CONF_BASE}/${INSTANCE}.d/config.ldap pidfile=/var/run/slapd.${INSTANCE} /usr/sbin/slapd -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${CONF_BASE}/${INSTANCE}.d -n ${INSTANCE
Our complete startup script would be this one :
#!/bin/bash # # --------------------------------------------------------------------- SLAPD=/usr/sbin/slapd CONF_BASE=/srv/conf/openldap if [ -z "$2" ] ; then echo -n "LDAP Instance : " read INSTANCE else INSTANCE=$2 fi if [ -f ${CONF_BASE}/${INSTANCE}.d/config.ldap ] ; then source ${CONF_BASE}/${INSTANCE}.d/config.ldap else echo "Configuration file ${CONF_BASE}/${INSTANCE}.d/config.ldap not found" echo "Exiting..." exit 1 fi pidfile=/var/run/slapd.${INSTANCE} start_ldap() { echo "Starting LDAP Instance ${INSTANCE}" ${SLAPD} -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${CONF_BASE}/${INSTANCE}.d -n ${INSTANCE} } # Stop slapd daemon stop_ldap() { echo "Stop LDAP instance ${INSTANCE}" SLAPPID=$(ps -fe|grep ${INSTANCE}.d|grep -v grep|awk '{print $2}' ) kill $SLAPPID } case "$1" in start) start_ldap ;; stop) stop_ldap ;; restart|force-reload) stop_ldap start_ldap ;; *) echo "Usage: $0 {start|stop|restart|force-reload}" exit 1 ;; esac