This documentation explains how Virtualmin can be setup to store users and mail aliases in an LDAP database, rather than using files in /etc as it does by default. It is particularly useful when you want to spread the load of virtual hosting across multiple systems, and need to them to all stay in sync.
LDAP (Lightweight Directory Access Protocol) is a way for clients to query and update a flexibly structured heirachial database. In the Unix world, it is most commonly used to distribute user and group information from a central server to many client systems, so that users can login to any client. Typically it is combined with NFS, which makes user home directories available on all clients too.
Each object in the database has a DN (distinguished name), which is formatted like:
cn=joe,dc=example,dc=com
As you can see, the DN is split into components, each of which is one element of the heirarchy. Most DNs are based on an internet domain name, although it is possible to use an organization's structure instead.
Each object in an LDAP database has one or more object classes. These determine what type of user it is, such as posixAccount for a Unix user, or posixGroup for a group. Users who have additional shadow password information will have the class shadowAccount too.
Each object has a list of attributes, each of which has a name and value. Typical attributes for Unix users are uid for the username, homeDirectory, loginShell and userPassword. The attributes allowed for each object differ depending on the object's classes.
When a client connects to an LDAP server, it can either authenticate itself with a DN and password, or connect anonymously. The server's configuration determines which are allowed, and which objects and attributes a client is allowed to read or write based on this DN.
The popular OpenLDAP server has a special root DN which has read/write access to everything in the database. This DN does not even have to exist in the database, as it is defined in the server's configuration file.
An LDAP server is responsible for managing the data files that make up an LDAP database, and providing access to that data to clients via the network. The most popular free LDAP server is OpenLDAP (http://www.openldap.org/), which is available for pretty much all Unix-like operating systems.
If you are running a CentOS, Fedora or Redhat Enterprise system, OpenLDAP can be installed with the command :
yum install openldap openldap-servers openldap-devel openldap-clients perl-LDAP
On CentOS, Fedora and Redhat Enterprise systems, the built-in LDAP server configuration will be used by default, which is not optimal for high-performance environments. To use a better configuration, run these commands :
cp /etc/openldap/DB_CONFIG.example /var/lib/ldap/DB_CONFIG /etc/init.d/ldap start
On an Ubuntu or Debian system, the command to use is :
apt-get install slapd php-net-ldap
On other operating systems, you will probably have to download, compile and install OpenLDAP manually. You should also install the Net::LDAP Perl module, which Webmin and Virtualmin need to talk to the server.
This module allows you to configure an OpenLDAP server, manage objects in its database, and setup access control for objects. It can be found in Webmin under the Servers category. By default, it should be configured automatically to find the OpenLDAP package provided by the your Linux distribution vendor.
Before the LDAP server can be used to store users and groups, a few configuration steps must be performed. These can be skipped if you have already manually setup the server.
foo.com you would enter dc=foo,dc=com .nis schema is checked.
Verify that the server is running and serving your base DN by clicking on the Browse Database icon. You should see the attributes of your new base object, which will have a class like domain.
Since we want the LDAP server to remain running from now on, on the module's main page select Yes next to the Start at boot button, and click it. This will enable the /etc/init.d script provided by your Linux distribution.
Now you have a root DN, you will want to create another DN under it to contain your LDAP users. This can be considered like a sub-directory, and even though you could create all objects under one DN, it isn't particularly neat and will slow down database searches.
To create a new DN for users, do the following :
If all goes well, the Users DN will be created, and an example Unix user object created under it. You can see them by navigating around on the Browse Database page.
You should then repeat the same steps to create a sub-tree for LDAP groups :
Most Unix-like operating systems (including Linux) can query an LDAP database for user and group information, which is then used by all programs and servers on the system. This means that LDAP users can login via SSH and FTP, own files, run processes and do everything that a user in /etc/passwd can do.
On Linux, NSS (Name Service Switch) is the library that determines where user and group information comes from. On a typical system only the /etc/passwd and /etc/group files were used, but because NSS is extensible it is possible to add support for any type of data source. Another that is often used is NIS, which has a similar client-server architecture to LDAP, but is losing popularity in favour of LDAP.
Before your system can fetch users from an LDAP database, the NSS module for it must be installed. On a CentOS, Fedora or Redhat system the command to do this is :
yum install nss_ldap
While on Debian or Ubuntu Linux, the command to use is :
apt-get install libnss-ldap
When run from the command line, this may ask several questions about the hostname of the LDAP server, the root DN and administration login. You should be able to answer them all based on the LDAP server setup done above.
PAM is a set of libraries and configuration files similar to NSS, but it deals only with passwords. It was designed to make the implementation of alternate authentication types (like RSA tokens or networked user databases) easier. Because you want users in the LDAP database to be able to login, you will need to install the a PAM module for it.
On Debian or Ubuntu Linux, the command to install is :
apt-get install libpam-ldap
When run from the command line, this may ask several questions about the LDAP root DN and administration login. The answers should be the same as what you gave to the libnss-ldap package.
For reasons unknown to me, Debian and Ubuntu systems have two separate configuration files for LDAP integration, one for NSS and one for PAM - even though they really should contain the same information. To reduce your system to using just one, run the commands :
mv /etc/pam_ldap.conf /etc/pam_ldap.conf.old ln -s /etc/libnss-ldap.conf /etc/pam_ldap.conf
On CentOS, Fedora or Redhat systems the needed PAM libraries are part of the nss_ldap package that you should have already installed in the previous step.
By now, you should have an LDAP database running with an example user in it. Your system has to be configured to actually use this database, which is best done using Webmin's LDAP Client module (found under the System category).
First, your system has to be told which LDAP server to use. To do this :
localhost in the Hostname field.Next, your system needs to know where in the LDAP database to find users :
At this point, you should be able to click on the LDAP Browser icon in this module and see the user and group sub-trees in your database. If it displays an error, check the settings made in the steps above.
Finally, the system has to be told to use LDAP to find user and group details. To enable this :
To verify that everything is really working, click the Validate Configuration button on the main page of the LDAP Client module. It should find and display the example Unix user that was created when you setup your LDAP server. If not, use the error message to work out what might have gone wrong.
If you get an error like user does not exist even when you are sure everything is correct, try restarting Webmin with the /etc/webmin/restart command run as root at the command line. On some systems, user and group data sources are cached by running server processes until they are restarted.
These same steps can be repeated on any other system on your network that should share users and groups. Naturally, they will also need to NSS and PAM LDAP modules installed too. These other systems should share the base directory for users' homes (typically /home) via NFS, so that users can login to any LDAP client and access their files.
On some systems (notably Debian and Ubuntu), the www-data user Apache runs as cannot be a member of any domains' groups, which prevents websites from working in a default Virtualmin setup. To fix this, edit the /etc/ldap.conf file, find the nss_initgroups_ignoreusers line and remove www-data from it.
NFS can be setup by using the NFS Exports module to share /home to the other client systems, and the Disk and Network Filesystems module on clients to add an NFS filesystem that mounts it. Typically one system will be both the LDAP and NFS server, but that doesn't strictly have to be case, as long as they can all write to /home.
PAM has it's own configuration files that determine when LDAP is used to check and change passwords. Unless they are setup, users created in LDAP will exist but will not be able to login. A command like id -a example will display a user from LDAP, but you will not be able to change his password with a command like passwd example.
This can be setup in Webmin's PAM Authentication module, found under the System Category. The exact steps to take differ slightly between Redhat-based and Debian-based distributions though. Once they are done, you should be able to use the passwd command to set a password for the example user.
Debian-based systems have a separate PAM include file for each step. LDAP support needs to be added to each as follows :
pam_ldap.so from the Add step for menu, then click the button.pam_ldap.so step above the existing pam_unix.so entry.These same steps should then be repeated for the common-auth, common-password and common-session services.
Redhat-based systems have a single common PAM service that is called by all others. LDAP support can be added to it as follows :
pam_ldap.so from the Add step for menu, then click the button.pam_ldap.so step above the existing pam_unix.so entry.Even though you could theoretically add a user to an LDAP database using the LDAP Server module's browser, it is much easier to use a Webmin module that takes care of selecting all the correct attributes for you. The LDAP Users and Groups module under the System category is similar to the more commonly used Users and Groups module, but operates directly on a local or remote LDAP database.
Assuming that your system has been setup as an LDAP client, when you open the module it should display a list of existing users and groups, including the example user. If it displays an error about connecting to the database or searching for users, you may need to adjust settings on the Module Config page.
To ensure that user creation is working, try clicking on Add a new LDAP user, filling in the Username, Real name and Password, and clicking Create. If the user is added to the list with no errors, and if you can SSH into the system as the user, congratulations!
If you get an error like no strucutural object class provided when adding a user, the cause is almost certainly that your LDAP schema requires that users have the person object class. Webmin versions 1.404 and later add this automatically, but to have it added in older versions you should do the following :
sn: ${REAL}
Once the LDAP Users and Groups module is working, you can configure Virtualmin to add new domain users and mailboxes to LDAP instead of files in /etc. This can be done as follows :
nscd action. If you see it, check the box next to it and then click Disable Now and On Boot. The Name Service Caching Daemon causes problems for Virtualmin, as it adds delay between when a user is added to the database and when it becomes visible to other programs.Any domains or mailboxes created from now on will be added to LDAP. To avoid confusion, I suggest only making this change on a system that isn't hosting any domains yet, so that they are all added to the same database.
The most common error is something like failed to create administration user or administration user was created but does not exist. This means that Virtualmin added an LDAP entry successfully, but when it used the getpwnam system call to check if the user is really known to Unix, he was not found. The most common cause is an incorrect LDAP client configuration, which should be revealed by the Validation Configuration button in the LDAP Client module. Another common cause is the nscd daemon, which adds a delay before users are visible and should be disabled.
Just as users and groups can be stored in LDAP, so can email aliases used by mail servers like Postfix. These can then be read by multiple mail servers sharing the same configuration, to distribute the mail delivery load.
These instructions assume that you already have a working LDAP server as explained above, but don't require that the system be setup to use LDAP for users or groups. Also, only Postfix is covered (even though Sendmail has similar capabilities), as only the Postfix Webmin module supports LDAP at the time of writing.
Postfix stores aliases, virtual address mappings and other configuration tables in maps, which are typically DBM format files built from text files. However, with the right plugin modules it can use a MySQL or LDAP database instead, which can be queried over the network.
On Debian or Ubuntu systems, the command to install LDAP support for Postfix is :
apt-get install postfix-ldap
On other systems, Postfix may come with LDAP support already enabled. If not, you may need to download and compile it manually. To check if your Postfix supports LDAP, run the command :
postconf -m
and look for ldap in the output.
I've found that there doesn't seem to be any consistent agreement on which LDAP object class and attributes to use for Postfix objects. However, the misc schema that comes with OpenLDAP defines a inetLocalMailRecipient class that is almost good enough.
To configure the schema fully, do the following :
misc schema (if it isn't already), and click Save.misc schema.inetLocalMailRecipient class, which should be like :
objectclass ( 2.16.840.1.113730.3.2.147 NAME 'inetLocalMailRecipient' DESC 'Internet local mail recipient' SUP top AUXILIARY MAY ( mailLocalAddress $ mailHost $ mailRoutingAddress ) )
AUXILIARY to STRUCTURAL, and click Save.
Each Postfix map should have a separate sub-tree in the LDAP database. With Virtualmin, you will need at least trees for the alias and virtual maps, which can be created as follows :
Now that the LDAP server is set, Postfix has to be told to talk to it. The first step is to have it use the correct LDAP object class, by doing :
Now you need to edit the maps for aliases and virtual domains to add LDAP data sources, as follows :
hash:/etc/aliases.It is also possible to use a different login, such as an LDAP account who just has read-write access to the aliases sub-tree.
You must now do the same thing on the Virtual Domains page. The only difference should be in the LDAP search base DN field, which should be set to something like dc=Virtual,dc=foo,dc=com .
To verify that everything is working, try adding an alias using Webmin and ensure that it shows up in the list of aliases. Then send email to the new alias, and check that it is forwarded correctly. If not, check the Postfix logs in /var/log/mail* for errors that explain why it couldn't talk to the LDAP database.
Once Webmin's Postfix module is configured to use LDAP, Virtualmin should automatically detect this and create any new aliases in the same LDAP database. To verify that it is all working, click on Re-Check Config on the left menu, and look for any messages about problems talking to the database server.
If that all checks out OK, try adding a mail aliases in Virtualmin, sending email to it, and verifying that it is delivered OK. Do the same for a mailbox user, as each has at least one virtual map entry for his address.
If you plan to run more than one mail server, each must have the same LDAP map configuration. This can be simplified by just copying across the configuration files in /etc/postfix that you will see referenced in the map definitions.