Kolab 3.3 Multi-Domain Setup on CentOS 7


Today we’re showing how to extend the single domain setup done earlier to get a truly multi domain Kolab install. You should probably reserve a couple of hours as there are quite some changes to do and not everything totally trivial. Also, if you’ve not read the blog about single domain setup, now is a good time :)

First of all, you can find the official documentation here. It’s probably a good idea to read it as well. We start with the easy parts and end with postfix, which needs the most changes. At the very end there are a couple of things that may or may not be issues you should be aware of.

Change Amavisd

We tell amavisd to accept all domains.

vi /etc/amavisd/amavisd.conf
# Replace that line
@local_domains_maps = ( [".$mydomain"] );
# With this line
$local_domains_re = new_RE( qr'.*' );

Change Cyrus IMAPD

Tell the IMAP server how to find our other domains. Add the following to the bottom of /etc/imapd.conf

ldap_domain_base_dn: cn=kolab,cn=config
ldap_domain_filter: (&(objectclass=domainrelatedobject)(associateddomain=%s))
ldap_domain_name_attribute: associatedDomain
ldap_domain_scope: sub
ldap_domain_result_attribute: inetdomainbasedn

Change Roundcube (webmail)

Basically you need to change the base_dn at several places. The placeholder ‘%dc’ is replaced during run-time with the real domain the user belongs to.

To save me some typing I’m pasting the diff output produced by git here. So it looks more than it actually is…

diff --git a/roundcubemail/password.inc.php b/roundcubemail/password.inc.php
index c3d449c..eafc8e5 100644
--- a/roundcubemail/password.inc.php
+++ b/roundcubemail/password.inc.php
@@ -45,7 +45,7 @@

     // LDAP base name (root directory)
     // Exemple: 'dc=exemple,dc=com'
-    $config['password_ldap_basedn'] = 'ou=People,dc=skolar,dc=de';
+    $config['password_ldap_basedn'] = 'ou=People,%dc';

     // LDAP connection method
     // There is two connection method for changing a user's LDAP password.
@@ -99,7 +99,7 @@
     // If password_ldap_searchDN is set, the base to search in using the filter below.
     // Note that you should comment out the default password_ldap_userDN_mask setting
     // for this to take effect.
-    $config['password_ldap_search_base'] = 'ou=People,dc=skolar,dc=de';
+    $config['password_ldap_search_base'] = 'ou=People,%dc';

     // LDAP search filter
     // If password_ldap_searchDN is set, the filter to use when
diff --git a/roundcubemail/calendar.inc.php b/roundcubemail/calendar.inc.php
index 98be7b9..8f98f8a 100644
--- a/roundcubemail/calendar.inc.php
+++ b/roundcubemail/calendar.inc.php
@@ -22,11 +22,11 @@
             'hosts'                 => 'localhost',
             'port'                  => 389,
             'use_tls'               => false,
-            'base_dn'               => 'ou=Resources,dc=skolar,dc=de',
+            'base_dn'               => 'ou=Resources,%dc',
             'user_specific'         => true,
             'bind_dn'               => '%dn',
             'bind_pass'             => '',
-            'search_base_dn'        => 'ou=People,dc=skolar,dc=de',
+            'search_base_dn'        => 'ou=People,%dc',
             'search_bind_dn'        => 'uid=kolab-service,ou=Special Users,dc=skolar,dc=de',
             'search_bind_pw'        => 'xUlA7PzBZnRaYV4',
             'search_filter'         => '(&(objectClass=inetOrgPerson)(mail=%fu))',
diff --git a/roundcubemail/config.inc.php b/roundcubemail/config.inc.php
index bfbfba3..60dc0b2 100644
--- a/roundcubemail/config.inc.php
+++ b/roundcubemail/config.inc.php
@@ -6,7 +6,7 @@

     $config['session_domain'] = '';
     $config['des_key'] = "FMlzG7LeqiUSOSK2T8xKQTHR";
     $config['use_secure_urls'] = true;
     $config['assets_path'] = 'assets/';

@@ -154,11 +154,11 @@
                     'hosts'                     => Array('localhost'),
                     'port'                      => 389,
                     'use_tls'                   => false,
-                    'base_dn'                   => 'ou=People,dc=skolar,dc=de',
+                    'base_dn'                   => 'ou=People,%dc',
                     'user_specific'             => true,
                     'bind_dn'                   => '%dn',
                     'bind_pass'                 => '',
-                    'search_base_dn'            => 'ou=People,dc=skolar,dc=de',
+                    'search_base_dn'            => 'ou=People,%dc',
                     'search_bind_dn'            => 'uid=kolab-service,ou=Special Users,dc=skolar,
                     'search_bind_pw'            => 'xUlA7PzBZnRaYV4',
                     'search_filter'             => '(&(objectClass=inetOrgPerson)(mail=%fu))',
@@ -196,7 +196,7 @@
                             'photo'             => 'jpegphoto'
                         ),
                     'groups'                    => Array(
-                            'base_dn'           => 'ou=Groups,dc=skolar,dc=de',
+                            'base_dn'           => 'ou=Groups,%dc',
                             'filter'            => '(&' . '(|(objectclass=groupofuniquenames)(obj
                             'object_classes'    => Array("top", "groupOfUniqueNames"),
                             'member_attr'       => 'uniqueMember',
diff --git a/roundcubemail/kolab_auth.inc.php b/roundcubemail/kolab_auth.inc.php
index 9fb5335..8eff518 100644
--- a/roundcubemail/kolab_auth.inc.php
+++ b/roundcubemail/kolab_auth.inc.php
@@ -8,7 +8,7 @@
         'port'                      => 389,
         'use_tls'                   => false,
         'user_specific'             => false,
-        'base_dn'                   => 'ou=People,dc=skolar,dc=de',
+        'base_dn'                   => 'ou=People,%dc',
         'bind_dn'                   => 'uid=kolab-service,ou=Special Users,dc=skolar,dc=de',
         'bind_pass'                 => 'xUlA7PzBZnRaYV4',
         'writable'                  => false,
@@ -26,11 +26,14 @@
         'sizelimit'                 => '0',
         'timelimit'                 => '0',
         'groups'                    => Array(
-                'base_dn'           => 'ou=Groups,dc=skolar,dc=de',
+                'base_dn'           => 'ou=Groups,%dc',
                 'filter'            => '(|(objectclass=groupofuniquenames)(objectclass=groupofurl
                 'object_classes'    => Array('top', 'groupOfUniqueNames'),
                 'member_attr'       => 'uniqueMember',
             ),
+        'domain_base_dn'           => 'cn=kolab,cn=config',
+        'domain_filter'            => '(&(objectclass=domainrelatedobject)(associateddomain=%s))',
+        'domain_name_attr'         => 'associateddomain',
     );

Change Postfix

Now this is actually the hardest part that requires the most changes. Initially I thought there would be a way around that, but it looks like it is currently really needed.

First we apply a couple of changes that allows us to have multiple domains besides our management domain (the domain we used to install Kolab). However those changes will not support domains having aliases. E.g. having the domain kodira.de with an alias of tourschall.com. To get domains with working aliases, we need to do even more.

Postfix Part 1 (basics)

Please follow the instructions given in the official documentation here. I don’t really see how I could write that part better or more compact. Do all the changes for: mydestination, local_recipient_maps, virtual_alias_maps and transport_maps.

Now, if you don’t need aliases, you’re basically done and you can skip the next section.

Postfix Part 2 (alias domains)

For each domain that should support alias domains we need to add 4 files. We’re doing this based on the following example.

  • Domain: kodira.de
  • Alias: tourschall.com

First create the directory /etc/postfix/ldap/kodira.de (name of the real domain)

In that directory create the following 4 files, but do not just copy&past them. You have to adjust them to your setup.

# local_recipient_maps.cf
# Adjust domain, bind_dn, bind_pw
server_host = localhost
server_port = 389
version = 3
search_base = cn=kolab,cn=config
scope = sub
domain = ldap:/etc/postfix/ldap/kodira.de/mydestination.cf
bind_dn = uid=kolab-service,ou=Special Users,dc=skolar,dc=de
bind_pw = XXX
query_filter = (&(|(mail=%s)(alias=%s))(|(objectclass=kolabinetorgperson)(|(objectclass=kolabgroupofuniquenames)(objectclass=kolabgroupofurls))(|(|(objectclass=groupofuniquenames)(objectclass=groupofurls))(objectclass=kolabsharedfolder))(objectclass=kolabsharedfolder)))
result_attribute = mail
# mydestination.cf
# Adjust bind_dn, bind_pw, query_filter
server_host = localhost
server_port = 389
version = 3
search_base = cn=kolab,cn=config
scope = sub
bind_dn = uid=kolab-service,ou=Special Users,dc=skolar,dc=de
bind_pw = XXX
query_filter = (&(associatedDomain=%s)(associatedDomain=kodira.de))
result_attribute = associateddomain
# transport_maps.cf
# Adjust domain, bind_dn, bind_pw
server_host = localhost
server_port = 389
version = 3
search_base = cn=kolab,cn=config
scope = sub
domain = ldap:/etc/postfix/ldap/kodira.de/mydestination.cf
bind_dn = uid=kolab-service,ou=Special Users,dc=skolar,dc=de
bind_pw = XXX
query_filter = (&(|(mailAlternateAddress=%s)(alias=%s)(mail=%s))(objectclass=kolabinetorgperson))
result_attribute = mail
result_format = lmtp:unix:/var/lib/imap/socket/lmtp
# virtual_alias_maps.cf
# Adjust search_base, domain, bind_dn, bind_pw
server_host = localhost
server_port = 389
version = 3
search_base = dc=kodira,dc=de
scope = sub
domain = ldap:/etc/postfix/ldap/kodira.de/mydestination.cf
bind_dn = uid=kolab-service,ou=Special Users,dc=skolar,dc=de
bind_pw = XXX
query_filter = (&(|(mail=%s)(alias=%s))(objectclass=kolabinetorgperson))
result_attribute = mail

Almost done, but don’t forget to reference those files from /etc/postfix/main.cf.

The bad news is: you have to add and adjust those 4 files for each domain which should support aliases. But the good news is: once configured you can use as many aliases for that domain as you want. No need to change config files for that.

Postfix Part 3 (finishing up)

Restart all services or just reboot the machine. Most things should work now, but there are a couple of points you still might need to take care about.

  1. In our main.cf there have been references to some catchall maps that we do not use and that do not exist on the file system. Therefore postfix stopped looking at the rest of that maps. We simply deleted the catchall references from main.cf and got rid of that problem.
  2. In our setup we had an issue with a domain having an alias with more then two parts. E.g. mail.kodira.de. As we don’t need addresses in the form of user@host.domain.tld we removed this alias and thus solved the problem.

Create domains and users using WAP

Now you should be able to use the ‘Kolab Web Administration Panel’ (WAP) to create domains and users.

  1. Go to http://<yourserver>/kolab-webadmin
  2. Login as ‘cn=Directory Manager’
  3. Go to ‘Domains’ and add a domain (simply giving it a name is enough)
  4. If you want add an alias to this domain by clicking the ‘+’ sign
  5. Logout
  6. Login again as ‘cn=Directory Manager’
  7. In the top right corner you should be able to select your newly created domain. Select it.
  8. Go to ‘Users’ and add a user to your new domain
  9. If you want, give the user the role ‘kolab-admin’. If you do, that user is able to log into WAP and to administrate that domain. For that login you should not use LDAP notation, but simply user@domain.tld.

Now maybe create a couple of test users on various domains and try to send some mails back and forth. It should work. If not have a look at those log files:

  • /var/log/maillog
  • /var/log/dirsrv/slapd-mail/access

Also do a grep for ‘kodira’, ‘tourschall’, ‘example’ in /etc/ to make sure you didn’t accidentally forgot to change some example configuration. Last but not least, think about putting /etc/ into a git repository – that will help you to review and restore changes you’ve made.

Good luck and have fun :)