This tutorial exists for these OS versions
- Ubuntu 18.04 (Bionic Beaver)
- Ubuntu 14.04 LTS (Trusty Tahr)
- Ubuntu 9.10 (Karmic Koala)
- Ubuntu 8.10 (Intrepid Ibex)
- Ubuntu 8.04 (Hardy Heron)
On this page
Postfix Virtual Hosting With LDAP Backend And With Dovecot As IMAP/POP3 Server On Ubuntu Kamic Koala 9.10
This how to will allow you step by to configure a Postfix mail server with with virtual hosting. Virtual hosting means that you can add as many mail domains as you want and sub sequentially as many mailboxes for these domains as you want.
Here we we use an LDAP backend for both the MTA (Postfix) and POP3/IMAP server (Dovecot), and a web based management interface.
Optional in this how to is the use of Roundcube webmail and proftpd.
The new version of Roundcube 0.3 allows a webmail user to change his / her (ldap) password, integrate an ldap address book and vacation using ldap (plugin). These features align nicely with the setup used in this how to and also provides an easy interface for the mail user.
This how to is an upgraded and enhanced version of the Ubuntu Intrepid version. Please note that the configuration of Roundcube and Proftpd can be added to a Intrepid / Jaunty setup.
Software to be used in this how to:
Postfix MTA, Dovecot IMAP / POP3, OpenLDAP, Gnarwl as autoresponder (vacation), Proftpd as ftp server, Phamm as management interface, MySQL as database backend for the webmail and Roundcube as webmail.
This worked for me, but I cannot guarantee that this set up will work for you so this how to comes without any guarantee.
Assumptions:
This how to assumes the following configurations, if your installation differs from this, then replace the entries below with your actual configuration.
Mail delivery (mailboxes) path:
/home/vmail/domains
User vmail:
UID:1000, GID:1000
User postfix:
UID: 108, GID:108
OpenLDAP base dn:
dc=example,dc=tld
OpenLDAP admin account:
cn=admin,dc=example,dc=tld
Phamm search dn:
o=hosting,dc=example,dc=tld
A read only account for the o=hosting,dc=example,dc=tld tree:
cn=phamm,o=hosting,dc=example,dc=tld
You're using root as the user during this guide.
If you want for example o=maildomains or ou=domains, please make sure to replace o=hosting with what you want, especially in the acl.ldif. This acl file is strict, phamm will not work correctly if it is not exactly as it should be. If you want a different read only user than phamm than replace cn=phamm with cn=wat-you everywhere in this how to.
Step 1: Install And Configure Ubuntu Server
I recommend following the guide below for this (I do not need to rewrite or reinvent what others did better than me) :
The Perfect Server - Ubuntu 9.10 [ISPConfig 3]
Replace the following on page 4:
aptitude install postfix postfix-mysql postfix-doc mysql-client mysql-server courier-authdaemon courier-authlib-mysql courier-pop courier-pop-ssl courier-imap courier-imap-ssl libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl getmail4 rkhunter binutils
by
aptitude install postfix postfix-ldap mysql-client mysql-server dovecot-imapd dovecot-pop3d libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl getmail4 rkhunter binutils
and skip the configuration of postfix. We will install and configure Postfix and Dovecot further on in this guide.
Note: all of the URLs and package names are valid at the time of writing of this how to. Best practice is to check if there are new versions available.
The directory names for the downloaded and extracted packages need to be changed to ver version number of the respective packages downloaded eg: phamm-0.5.17 to phamm-0.5.xx
So let's get started with the rest.
Download some packages and openldap schema's we will need:
cd /usr/src
Get the latest version of phamm:
wget http://open.rhx.it/phamm/phamm-0.5.17.tar.gz
Unpack the archive:
tar xvzf phamm-0.5.17.tar.gz
Step2: Install and configure openldap
The configuration of OpenLDAP got a bit (more) complicated. cn=config is still used, but when installing the packages from the repositories only a skeleton configuration of openldap is installed.
You're not asked anymore to provide a password when the package is installed and issuing the "dpkg-reconfigure slapd" only resest openldap to the skeleton configuration. You will have to setup the openldap database, root dn and acl's your self using the root account (or sudo) in order to configure openldap.
Install openldap and ldap-utils:
aptitude install slapd ldap-utils
Change into the /etc/ldap directory:
cd /etc/ldap
Copy the phamm.schema and perversia.net.schema from the phamm package to the schema directory:
cp /usr/src/phamm-0.5.17/schema/phamm.schema /etc/ldap/schema.
cp /usr/src/phamm-0.5.17/schema/contrib/perversia.net.schema /etc/ldap/schema.
Get some more schema's we need.
cd schema
wget http://open.rhx.it/phamm/schema/ISPEnv2.schema
wget http://open.rhx.it/phamm/schema/amavis.schema
wget http://open.rhx.it/phamm/schema/pureftpd.schema
cd ../
Now we need to convert the schema's to ldif format.
Create a file called convert and paste the text below in to it.
vi convert
Contents of convert:
include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/phamm.schema include /etc/ldap/schema/ISPEnv2.schema include /etc/ldap/schema/amavis.schema include /etc/ldap/schema/pureftpd.schema include /etc/ldap/schema/perversia.net.schema
Now we will convert the shemas:
mkdir ldif
slaptest -f convert -F ldif
Now we change in to the directory that contains the converted schemas:
cd ldif/cn\=config/cn\=schema
The directory should contain the following files:
cn={0}core.ldif cn={3}inetorgperson.ldif cn={6}amavis.ldif
cn={1}cosine.ldif cn={4}phamm.ldif cn={7}pureftpd.ldif
cn={2}nis.ldif cn={5}ISPEnv2.ldif cn={8}perversia.ldif
We will need to edit the phamm, amavis, pureftpd, ISPEnv2 and perversia schemas. For each you need to do the following (example for the phamm schema):
Change:
dn: cn={4}phamm objectClass: olcSchemaConfig cn: {4}phamm
to
dn: cn=phamm,cn=schema,cn=config objectClass: olcSchemaConfig cn: phamm
And delete:
structuralObjectClass: olcSchemaConfig entryUUID: c27532b2-6a27-102e-88a5-e92372c94d84 creatorsName: cn=config createTimestamp: 20091120135300Z entryCSN: 20091120135300.238121Z#000000#000#000000 modifiersName: cn=config modifyTimestamp: 20091120135300Z
So for each of these do repectively and make the changes like above:
vi cn\=\{4\}phamm.ldif
vi cn\=\{5\}ISPEnv2.ldif
vi cn\=\{6\}amavis.ldif
vi cn\=\{7\}pureftpd.ldif
vi cn\=\{8\}perversia.ldif
Note: the enry phamm in the example is ISPEnv2, amavis, pureftpd and pervisia in the other ldif's.
Now we copy the ldifs to the /etc/ldap/schema directory (this is not needed, but is handy whenever the ldif's are needed).
cp cn\=\{4\}phamm.ldif /etc/ldap/schema/phamm.ldif
cp cn\=\{5\}ISPEnv2.ldif /etc/ldap/schema/ISPEnv2.ldif
cp cn\=\{6\}amavis.ldif /etc/ldap/schema/amavis.ldif
cp cn\=\{7\}pureftpd.ldif /etc/ldap/schema/pureftpd.ldif
cp cn\=\{8\}perversia.ldif /etc/ldap/schema/perversia.ldif
We can now delete the ldif directory since we don't need it anymore and also to avoid any confusion and change back to the /etc/ldapdirectory.
cd /etc/ldap
rm -R ldif
Now we add the schemas to openldap.
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/phamm.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ISPEnv2.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/amavis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/pureftpd.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/perversia.ldif
We need load the database backend module and create the database.
Create a file called db.ldif and paste the text below in to it:
vi db.ldif
Content of the db.ldif:
# Load dynamic backend modules dn: cn=module{0},cn=config objectClass: olcModuleList cn: module olcModulepath: /usr/lib/ldap olcModuleload: {0}back_hdb # Create the database dn: olcDatabase={1}hdb,cn=config objectClass: olcDatabaseConfig objectClass: olcHdbConfig olcDatabase: {1}hdb olcDbDirectory: /var/lib/ldap olcSuffix: dc=example,dc=com olcRootDN: cn=admin,dc=example,dc=com olcRootPW: example olcDbConfig: {0}set_cachesize 0 2097152 0 olcDbConfig: {1}set_lk_max_objects 1500 olcDbConfig: {2}set_lk_max_locks 1500 olcDbConfig: {3}set_lk_max_lockers 1500 olcLastMod: TRUE olcDbCheckpoint: 512 30 olcDbIndex: cn,mail,givenname eq,subinitial olcDbIndex: vd,delete eq,pres olcDbIndex: accountActive,forwardActive eq,pres olcDbIndex: smtpAuth eq,pres olcDbIndex: sn,displayName eq,pres,sub olcDbIndex: default sub olcDbIndex: uid eq,pres olcDbIndex: objectClass eq
Safe the file and issue the following command to load the module and initialize the database:
ldapadd -Y EXTERNAL -H ldapi:// -f db.ldif
Please note the olcRootPW: example which sets the RootPW to example. Replace example witch a password of your choice.
Now we create the base dn and the admin account for the openldap server as well as the o=hosting and phamm account.
Modify the text below to your needs and wants and generate a password for the admin account. The hash currently in this file sets the password to example. The crypt for the phamm account results in the password readonly.
To create crypt a password for the admin account issue the following command:
slappasswd -h {MD5}
Type the wanted pasword twice and copy the result in to the text below.
Create the base.ldif:
vi base.ldif
Content of base.ldif.
dn: dc=example,dc=tld objectClass: dcObject objectclass: organization o: example.tld dc: example description: My LDAP Root dn: cn=admin,dc=example,dc=tld objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin userPassword: {MD5}Gnmk1g3mcY6OWzJuM4rlMw== description: LDAP administrator dn: o=hosting,dc=example,dc=tld objectClass: organizationalUnit objectClass: top ou: domains description: Hosting Organization # Read only account dn: cn=phamm,o=hosting,dc=example,dc=tld objectClass: simpleSecurityObject objectClass: organizationalRole cn: phamm userPassword: {MD5}M267sheb6qc0Ck8WIPOvQA== description: Read only account
Load the base dn into the database with the following command:
ldapadd -Y EXTERNAL -H ldapi:// -f base.ldif
We modify the system acl's.
There are some acl's set in the openldap setup that prevent phpldapadmin to interface with the directory, so we will remove them now and set openldap to the default cn=admin,cn=config. From this moment on the openldap can be configured and manipulated as before, but no longer by issuing commands like ldapadd -Y EXTERNAL -H ldapi:// -f file but rather ldapadd -x -Y EXTERNAL -H ldapi:// -D cn=admin,cn=config -W -f file.
Create a file called config.ldif and paste the text below in to it. However do not forget to replace the olcRootPW hash with the hash you created above.
vi config.ldif
Content of config.ldif:
dn: cn=config changetype: modify delete: olcAuthzRegexp dn: olcDatabase={-1}frontend,cn=config changetype: modify delete: olcAccess dn: olcDatabase={0}config,cn=config changetype: modify delete: olcRootDN dn: olcDatabase={0}config,cn=config changetype: modify add: olcRootDN olcRootDN: cn=admin,cn=config dn: olcDatabase={0}config,cn=config changetype: modify add: olcRootPW olcRootPW: {MD5}Gnmk1g3mcY6OWzJuM4rlMw== dn: olcDatabase={0}config,cn=config changetype: modify delete: olcAccess
Load the config.ldif into the openldap server:
ldapadd -Y EXTERNAL -H ldapi:// -f config.ldif
Set the ldap acl's for phamm.
Create a file called acl.ldif and paste the text below into it:
vi acl.ldif
Content of acl.ldif:
dn: olcDatabase={1}hdb,cn=config add: olcAccess olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=userPassword by dn="cn=admin,dc=example,dc=tld" write by self write by anonymous auth by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" write by set.expand="user/vd & [$1]" write olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=amavisBypassVirusChecks,quota,smtpAuth,accountActive by dn="cn=admin,dc=example,dc=tld" write by self read by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by set.expand="user/editAccounts & [TRUE]" write by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" read by set.expand="user/vd & [$1]" write olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=cn,sn,uid,forwardActive,vacationActive,vacationInfo,vacationStart,vacationEnd,vacationForward,amavisSpamTagLevel,amavisSpamTag2Level,amavisSpamKillLevel by dn="cn=admin,dc=example,dc=tld" write by self write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" write by set.expand="user/vd & [$1]" write olcAccess: to dn.regex="^.*,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=editAccounts by dn="cn=admin,dc=example,dc=tld" write by self read by set.expand="user/editAccounts & [TRUE]" write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by * none olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=objectClass,entry by dn="cn=admin,dc=example,dc=tld" write by self write by anonymous read by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by set.expand="user/editAccounts & [TRUE]" write by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" read olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=amavisBypassSpamChecks,accountActive,delete by dn="cn=admin,dc=example,dc=tld" write by self read by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" write by set.expand="user/vd & [$1]" write olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=otherPath by dn="cn=admin,dc=example,dc=tld" write by anonymous read by self read by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by dn.exact,expand="cn=postmaster,vd=$1,o=hosting,dc=example,dc=tld" read by set.expand="user/vd & [$1]" write olcAccess: to dn.regex=".+,vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=createMaildir,vdHome,mailbox,otherTransport by dn="cn=admin,dc=example,dc=tld" write by self read by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by set.expand="user/vd & [$1]" read olcAccess: to dn.regex="^(.+,)?vd=([^,]+),o=hosting,dc=example,dc=tld$" attrs=vd by dn="cn=admin,dc=example,dc=tld" write by self write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by dn.exact,expand="cn=postmaster,vd=$2,o=hosting,dc=example,dc=tld" write by set.expand="user/vd & [$2]" write olcAccess: to dn.regex="^(.+,)?vd=([^,]+),o=hosting,dc=example,dc=tld$" by dn="cn=admin,dc=example,dc=tld" write by self write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by set.expand="user/editAccounts & [FALSE]" read by dn.exact,expand="cn=postmaster,vd=$2,o=hosting,dc=example,dc=tld" write by set.expand="user/vd & [$2]" write olcAccess: to dn.regex=".+,o=hosting,dc=example,dc=tld$" by dn="cn=admin,dc=example,dc=tld" write by self write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by anonymous auth olcAccess: to dn.regex=".+,dc=tld$" by dn="cn=admin,dc=example,dc=tld" write by dn.exact="cn=phamm,o=hosting,dc=example,dc=tld" read by anonymous auth olcAccess: to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=example,dc=tld" write by anonymous auth by self write by * none olcAccess: to dn.base="" by * read olcAccess: to * by dn="cn=admin,dc=example,dc=tld" write by * read
Now load the acl into the openldap server:
ldapmodify -x -D cn=admin,cn=config -W -f acl.ldif
Now we have openldap configured and we can go to the next step.