Ubuntu: Basic Mail Server Configuration

We will try to install and configure a mail server solution in Ubuntu. We will use postfix as the SMTP server and Dovecot as the IMAP/POP3 server. We will also use Thunderbird as the client agent for testing purpose. Before you could install a mail server, you need to have a running DNS server with an MX record in it for your domain. Refer to this post on how to configure a DNS server.

First, download and install postfix with the command

sudo apt-get install postfix

When the installation is done, you will be asked by several questions, answer them with the following:

  • Internet Site
  • mail1.example.com (change this to what you want your mail server name and domain name to be)
  • administrator (change this to the administrator username)
  • mail.example.com, example.com, localhost.example.com, localhost (you can leave it as default or change this to suit your mail server and domain name)
  • No
  • [::ffff:]/104 [::1]/128 (you can leave it as default)
  • 0
  • +
  • all

Now, change the mailbox format used to Maildir with the command.

sudo postconf -e 'home_mailbox = Maildir/'
sudo postconf -e 'mailbox_command ='

The Maildir format will place each mail as a file in /home/username/Maildir. Now, verify postfix installation with the command (change mail1.example.com to your mailserver name or any other name just for testing purpose)

telnet localhost 25
ehlo example.com

If you are connected and you get responses, then postfix is running. Before we test sending an email, let's install Dovecot as the IMAP/POP3 server. Get and install Dovecot with the following command

sudo apt-get install dovecot-imapd dovecot-pop3d

Now, some configuration changes needs to be done to /etc/dovecot/dovecot.conf. Open the file using your favourite text editor. First, we will set the protocol that will be used supported by dovecot, search for the following protocols entry and change the value to support which protocol that you prefer.

protocols = pop3 pop3s imap imaps

configure dovecot to use Maildir format, search for the mail_location entry (it is commented by default) and set the value to the following

mail_location = maildir:~/Maildir

To allow login from remote machine, search for the "listen" parameter and set it to

listen = *

For Thunderbird specific configuration, search for the IMAP configuration part "protocol imap {", then search for "imap_client_workarounds" parameter before the closing bracket. Change it to

imap_client_workarounds = tb-extra-mailbox-sep

Then, add the Maildir skeleton directory to /etc/skel to automatically create the Maildirr directory structure for newly created users. Run the following command

sudo maildirmake.dovecot /etc/skel/Maildir
sudo maildirmake.dovecot /etc/skel/Maildir/.Drafts
sudo maildirmake.dovecot /etc/skel/Maildir/.Sent
sudo maildirmake.dovecot /etc/skel/Maildir/.Trash
sudo maildirmake.dovecot /etc/skel/Maildir/.Templates

Now, restart Dovecot and test if it is running. Run the following command

sudo /etc/init.d/dovecot start
telnet localhost pop3
telnet localhost imap2

If Dovecot is running correctly, you should get respond when you're connecting to the POP3 and IMAP server. Next, is to try to connect to the mailserver by using a client agent. We will use Thunderbird, if you haven't installed Thunderbird, get and install it. I believe it is not hard to be found. Before start configuring Thunderbird, let's add a localuser named "joe" at the mailserver for testing purpose with the command

sudo useradd -m -s /bin/bash joe
sudo passwd joe

Now, let's configure Thunderbird so that joe can check his mail on the mailserver. Once you've installed Thunderbird on the client, run it, then click the File > New > Mail Account. A dialog box will appear to configure a new mail account, fill in the your name, email address and password (the value depends on what you've set for joe's password) to match joe's account

Click Continue, Thunderbird will try to resolv the POP3/IMAP server and the SMTP server for the domain. If Thunderbird failed to resolv the mail server, Then click Manual Configuration. On the Server Name, fill in the mail server's hostname or IP address. Choose the port number 110 for POP3 or 143 for IMAP. Choose STARTTLS at the Connection security and Normal Password at the Authentication Method. Then click OK

You will notice that Thunderbird will list your newly created account on the left hand side. Right click on the account name, in this case "joe@example.com", then click Settings. Make sure the selected server for Outgoing Server (SMTP) is correct, if not, you can manually add your SMTP server into Thunderbird. On the left hand side of the dialog, look for the most bottom entry, there will be an Outgoing Server (SMTP) entry. Click Add, Then fill in the server name, which is the SMTP hostname or IP addres. Choose the connection security settings and Authentication Method used by your SMTP server, in this example, choose STARTTLS and No Autentication respectively. Click OK, then go back to the account setting, and select the correct SMTP server at the Outgoing Server (SMTP) entry.

Now, you can add another user to the mail server local user for testing purpose, then try to send email from one to another. You will received the email in Thunderbird. For further enhancement, you will want to add authentication to postfix, therefore disabling spammers to use your SMTP server to send emails, Integrating Dovecot with LDAP for Single Sign-On, installing and configuring spam assasin.


Ubuntu: DNS Server

We will configure a DNS server on a Ubuntu machine. This server will act as the master DNS for the local domain in this example, which is example.com. First, get the bind9 and the utility package with the commands

sudo apt-get install bind9
sudo apt-get install dnsutils

Now, add the "zone" (domain) to /etc/bind/named.conf.local. Use your favourite text editor to edit that file. and add the following (you will need the super user privilege to edit the file).

zone "example.com" {
type master;
file "/etc/bind/db.example.com";

zone "1.168.192.in-addr.arpa" {
type master;
notify no;
file "/etc/bind/dbreverse.example.com";

From the above example, two zones are created. First is example.com zone. This zone will have entry of hosts stored in file /etc/bind/db.example.com, which will need to be created later. The second zone is 1.168.192.in-addr.arpa, the reverse zone which will holds the entry to resolv ip address to hostname. You need to change 1.168.192 with whatever private network address that you need in reverse order. If you use network, then the zone name must be 168.192.in-addr.arpa. Recognize that all of the db files are referenced with the absolute path, if relative path is given, bind9 will start finding the file from /var/cache/bind, like how it is configured in /etc/bind/named.conf.options.

Now, create the file, db.example.com in /etc/bind. Add the following to the file.

$TTL 604800
@ IN SOA ns.example.com. root.example.com. (
2011010101 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
@ IN NS ns.example.com.
@ IN MX 10 mail.example.com.

ns IN A
mail IN A
host1 IN A
gateway IN CNAME host1

In this file, the ";" sign mark the start of a comment, and whatever follows will be ignored by the DNS parser. The first line is the TTL value, this value tells how long does other DNS server can cache infomation queried from this server. The next line is the State of Authority record. The @ symbol is a shotcut for the zone name declared in /etc/bind/named.conf.local, IN specify that this DNS resource is the internet class. We will use this value most often. SOA should always be there. The next entry is the hostname of the DNS server that could provide DNS service for the domain. You can specify the FQDN of the nameserver, but remember to always put a dot at the end of the name server. The nxt entry is the email address of someone who is responsible of this zone, remember to always put a dot at the end of the entry if it is a FQDN. the next fields consists of several entries that are enclosed with a set of parenthesis. Those are

  • Serial. This number should always be incremented everytime a change has been made to the file. Most people will use the yyyymmddnn format, with the nn is the sequence number, giving you the feasible value of 00-99 for a day.
  • Refresh Interval. This is the value in seconds after which a slave DNS server will update its zone and reverse zone information from the master
  • Retry. This is the value in which if a slave DNS server failed to contact the master to update its zone and reverse information, should retry to contact the master after the amount of this value has elapsed. This value should be much smaller than the Refresh value.
  • Expiration. This is the amount of time which information in slave DNS server should be considered expired. If a slave DNS server failed to update its zone and reverse information and the amount of time in this entry has elapsed, it will stop responding queries asking information about this domain.
  • Negative Cache TTL. The amount of time that a negative response, such as a nonexistent domain response, will be cached by the DNS server.

The next part of the file is the entry that defines hostname to ip address. As can be seen, there is a nameserver, mail, host and alias entry. The nameserver record, marked with NS specify what is the name of the nameserver in this zone. The mx record, which is the mailserver record looks the same as the NS record except that it uses MX and there is a sequence number, in this case 10, specifying which mailserver will be preffered in the domain. Both of the records point to a hostname, therefore we need to specify the ip address of those hostname and that is done with the A record. The CNAME record specify an alias, in this example gateway is an alias for host1 and therefore, both will resolv to the same address. You can modify the value of this entries based on your requirement.

Next, create the reverse zone file information. Create the /etc/bind/dbreverse.example.com and fill the file with the following.

$TTL 604800
@ IN SOA ns.example.com. root.example.com. (
2011010101 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
@ IN NS ns.example.com.
133 IN PTR ns.example.com.
140 IN PTR mail.example.com.
1 IN PTR host1.example.com.

Basically, in the reverse zone file you have to create a PTR record for each A record in the zone file. Now restart bind9 with the command

sudo /etc/init.d/bind9 restart

Next, add an entry of your newly configured nameserver in /etc/resolv.conf. add the following line to the beginning of file


Change to whatever your DNS server ip address is. Then, you can verify your configuration by using the dig command. Try the following command,

dig ns.example.com

If your configuration is working, it should give an output similar to this

; <<>> DiG 9.7.0-P1 <<>> ns.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47515
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;ns.example.com. IN A

ns.example.com. 604800 IN A

example.com. 604800 IN NS ns.example.com.

;; Query time: 1 msec
;; WHEN: Sat Oct 2 21:21:32 2010
;; MSG SIZE rcvd: 62


Ubuntu: OpenLDAP

We will install OpenLDAP in Ubunt server. Here, I user Ubuntu server 10.04. After that we will use OpenLDAP for authentication. First, download and install OpenLDAP by using apt-get.

sudo apt-get install slapd ldap-utils

Next, load some schemas to LDAP (LDAP schemas give structure/attributes to LDAP classes, the following schemas will be used for adding users later)

sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif

Then, load the backend configuration to LDAP. Copy the following configuration to a file, name it backend.ldif

# Load dynamic backend modules
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /usr/lib/ldap

olcModuleload: back_hdb

# Database settings
dn: olcDatabase=hdb,cn=config

objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcSuffix: dc=example,dc=com
olcDbDirectory: /var/lib/ldap
olcRootDN: cn=admin,dc=example,dc=com
olcRootPW: adminpw
olcDbConfig: set_cachesize 0 2097152 0
olcDbConfig: set_lk_max_objects 1500
olcDbConfig: set_lk_max_locks 1500
olcDbConfig: set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcLastMod: TRUE
olcDbCheckpoint: 512 30
olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
olcAccess: to attrs=shadowLastChange by self write by * read
olcAccess: to dn.base="" by * read
olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read

Take a look at the olcSuffix, olcRootDN and the olcRootPW entry. The olcSuffix is the domain name, here we use example.com as the domain name. The olcRootDN is the DN that has the administrator privilege like. olcRootPW is the password for the root admin. You may want to change those value to meet your requirement. If everything is fine, load the configuration to LDAP with the command

sudo ldapadd -Y EXTERNAL -H ldapi:/// -f backend.ldif

Next, fill the frontend directory to LDAP. This is where we create our organization tree, the domain, ou, user, group, ect. Copy the following to a file named frontend.ldif

# Create top-level object in domain
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectclass: organization
o: Example Organization
dc: Example
description: LDAP Example

# Admin user.
dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: secret

dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups

dn: uid=john,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount

uid: john
sn: Doe
givenName: John
cn: John Doe
displayName: John Doe
uidNumber: 1000
gidNumber: 10000
userPassword: password
gecos: John Doe
loginShell: /bin/bash
homeDirectory: /home/john
shadowExpire: -1
shadowFlag: 0
shadowWarning: 7
shadowMin: 8
shadowMax: 999999
shadowLastChange: 10877
mail: john.doe@example.com
postalCode: 31000
l: Toulouse
o: Example
mobile: +33 (0)6 xx xx xx xx
homePhone: +33 (0)5 xx xx xx xx
title: System Administrator
initials: JD

dn: cn=example,ou=groups,dc=example,dc=com
objectClass: posixGroup
cn: example
gidNumber: 10000

In the example above, we create a user with uid: john. under the people oum the uid and the userPassword attributes will be used for authentication later. A group named example is also created under the groups ou and john is a member of that group. Change the value of ou, user information to meet your requirement. What should be taken into consideration here is the uidNumber attribute of the user. This uidNumber should be unique, it should not be the same with other user, even with the local user. You can check if the uidNumber has been used by local user by checking the "/etc/passwd" file. In above example, john's uidNumber is 1000. To check if this uid number has been used by local user, enter the following command

egrep ":1000:" /etc/passwd

If there's any output, then it has been used. If everything has been set, then load the frontend directory to OpenLDAP with the following command

sudo ldapadd -x -D cn=admin,dc=example,dc=com -W -f frontend.ldif

We have finished populating LDAP directory, next we will configure to use LDAP user for authentication

LDAP Authentication

To configure LDAP for authentication, first we need to install the libnss-ldap package.

sudo apt-get install libnss-ldap

After finishing the installation, you wll be asked several questions. Assume that you use the example.com as your domain, for each question enter the following answer

  • ldapi:///example.com
  • dc=example,dc=com
  • 3
  • No
  • No

Then, enable auth-client-config LDAP profile

sudo auth-client-config -t nss -p lac_ldap

Now, enable PAM for LDAP by the command

sudo pam-auth-update

Choose LDAP and any other authentication mechanism if needed. Now, you should be able to login using your OpenLDAP user, in this example, as john. But something still has to be done. If we recall from the user entry in frontend.ldif file, we specify the home directory of john to be "/home/john", but this directory is not exist yet (not if you have created it before). The problem here is that, since we are adding user from LDAP, user's home directory is not automatically created. This is different from adding local user with the "useradd -m " command.

Creating User's Home Directory

Using your favourite text editor, edit the file "/etc/pam.d/common-session". Add the following entry if not exist

session required pam_unix.so
session required pam_mkhomedir.so skel=/etc/skel/
session optional pam_ldap.so
session optional pam_foreground.so

Now, if you logged using your LDAP user for the first time, user's home directory will be created.