Wednesday, June 15, 2016

Making a Mailserver (Part 2) - My Personal Daemons: Exim and Dovecot

This is an instalment in my series on setting up a Linux based mailserver. See these posts:

The Boring Preamble

In this post, we set up exim4 as an mail receiver (and personal email relay) and dovecot as your secure IMAP service. Why use exim4 and dovecot? Because there's safety in numbers; these are tremendously popular daemons, have comprehensible config structures and are well documented. That documentation extends to a lot of user sites, like this blog, where people post their own experiences and suggestions.

Security is the primary concern. Dovecot provides secure IMAP, but I needed exim to allow me to relay my mail. If you blindly turn on mail relay then soon enough most of the population of Eastern Europe and various other countries will be using your server as a spam hub and malware pivot-point.
This image is deliberately vague, but it is definitely of mailboxes


A mail relay is a server that accepts mail for destinations that are not delivered locally to that server. A relay assumes the responsibility of sending that email on to its intended destination. Relay is what I needed, but I was reluctant to share my server bandwidth with spammers. It is possible to configure exim4 to be a mail relay only on behalf of authorised hosts and users.

But first, you need to get exim4 off the ground with the basic config. The exim4 setup wizard is really great. On debian you can invoke this with
dpkg-reconfigure exim4-config
The magic of this wizard is that you can run it over and over while you try to get the settings right. The wizard won't overwrite customisations you've made in the other config files, unless those customisations pertain specifically to questions in the wizard.

Setup Wizard Explanation

General type of mail configuration:
Select: internet site; mail is sent and received directly using SMTP
System mail name:
Do not put something like or!
IP-addresses to listen on for incoming SMTP connections:
Input nothing.
This is an Internet facing mail server, you can't reduce your risk here.
Other destinations for which mail is accepted:
Any other domains that you plan to receive mail for is added here. At this stage you probably want to leave this empty.
Domains to relay mail for:
It's really a good idea to leave this blank. If you wanted to accept and deliver mail for another domain and not deliver locally, then here is where you configure that. This may be like playing with fire if you are not in control of the domains that you list here. Don't confuse it with the "other destinations" question earlier, which is about local delivery.
Machines to relay mail for:
Input any host IP addresses that you control, for which you want to handle mail from. This is incredibly useful. You have several servers out on the Internet and you want them to be able to send email to the rest of the world, you can tell those servers to use this server as their "smarthost" mail relay. If you are going to set up Squirrelmail per my instructions then you must enter your own server's IP here. Squirrelmail in this setup will connect to Exim using the server's IP as its source.

Instead of trying to configure several servers with tight mail rules and dmarc policies, you need only configure this server and have your other servers relay their outgoing email here.
Keep number of DNS-queries minimal (Dial-on-Demand)?
Nobody cares, select "No".
Delivery method for local mail:
You probably want to select: "mbox format in /var/mail/"
Split configuration into small files?
Select "Yes". You end up with a mess of files, but in the long run I think it's better. The rest of this guide is based on this setting being enabled..

That's the last question. Now the basic framework of your mailserver is setup. The tricky secure lockdown is next.

With exim4, you can enable relay for the specific case where the sender is authenticated. In other words, if I can prove to my server that I am an authenticated person, then my server will relay my emails. When I connect to my mailserver to send email, I go through a username/password challenge.

You don't want to do the authentication over plain text, so encrypting the traffic is key to reducing the likelihood that someone will crack your username and password. That's what the STARTTLS method is for.

I'm not going into particular detail as to each setting, these you can look up for yourself in the exim4 documentation. Here's the step-by-step configuration. 

Adding the Security

Edit /etc/exim4/update-exim4.conf.conf and check that you can see this (if you can't, then you ignored my recommendation earlier and I can't help you anymore):
Now add these lines to the end of the file:
 Create a file called /etc/exim4/conf.d/main/00_my_macros and add this:
You'll be back in this file later if you set up DKIM via my setup guide.

Now edit /etc/exim4/conf.d/auth/30_exim4-config_examples and uncomment/setup this section:
 driver = plaintext
 public_name = PLAIN
 server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}"
 server_set_id = $auth2
 server_prompts = :
 server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}

Because you've made changes to the split config, run the config updater and then reload: 
service exim4 reload
At the time of writing, I am not sure whether both steps are really required.

Fake Certificate

In later posts, you'll find out how to attach a letsencrypt certificate (a real certificate) to apache, exim and dovecot. For now though, let's just get something working.

Generate your own certificate for exim to use in STARTTLS (debian example):
 /usr/share/doc/exim4-base/examples/exim-gencert --force
You'll need to answer some questions, you can't get them wrong. It's an untrusted (self signed) certificate. We'll get a real certificate sorted out later, via letsencrypt. One thing at a time.

The certs will hopefully be dumped into the /etc/exim4/ as exim.crt and exim.key. Debian-exim will need to be able to read this and you can't have an all readable flag
chmod 640 /etc/exim4/exim.*
chown root.Debian-exim /etc/exim4/exim.*
ls -l /etc/exim4/
-rw-r----- 1 root Debian-exim   790 Sep 16 14:12 exim.crt
-rw-r----- 1 root Debian-exim   891 Sep 16 14:12 exim.key

Troubleshooting exim4

There is an excellent debug mode that you can run exim in. If you have problems, stop exim and start it in debug mode:
/etc/init.d/exim4 stop  
exim -bd -d -oX 25
Of course, when you want to start exim normally again, use the "start" option instead of "stop".

Tail the exim 'mainlog' and 'rejectlog' logfiles in /var/log/exim4 as you test email delivery to your server.


Configuring dovecot is relatively straightforward and doesn't need a lot of explaining. The dovecot help pages are very good. Don't randomly google problems, check those pages first.

I don't have any notes from the first time I set up dovecot as it is getting on for a decade ago and the config evolved over time. Over all these years, there appear to have been no configuration syntax changes that have affected me, until I jumped from Debian 6 to Debian 8 (Jessie).

When I did server migrations in the past, I lazily copied the old dovecot config files into the new /etc/dovecot directory and miraculously dovecot still started. The same was true when I migrated to Debian 8.5. However, I was confronted by these messages in /var/log/syslog:
doveconf: Warning: NOTE: You can get a new clean config file with: doveconf -n > dovecot-new.conf
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:25: 'imaps' protocol can no longer be specified (use protocols=imap). to disable non-ssl imap, use service imap-login { inet_listener imap { port=0 } }
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:100: ssl_cert_file has been replaced by ssl_cert = <file
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:101: ssl_key_file has been replaced by ssl_key = <file
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:718: protocol managesieve {} has been replaced by protocol sieve { }
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:890: add auth_ prefix to all settings inside auth {} and remove the auth {} section completely
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:928: passdb pam {} has been replaced by passdb { driver=pam }
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:1041: userdb passwd {} has been replaced by userdb { driver=passwd }
doveconf: Warning: Obsolete setting in /etc/dovecot/dovecot.conf:1103: auth_user has been replaced by service auth { user }
I ran "doveconf -n > dovecot-new.conf" as suggested and the configuration was boiled down to this simple setup:
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = mbox:~/mail:INBOX=/var/mail/%u
mail_privileged_group = mail
passdb {
  driver = pam
protocols = imap
service auth {
  user = root
service imap-login {
  inet_listener imap {
    port = 0
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem
userdb {
  driver = passwd
#protocol imap {
#  mail_max_userip_connections = 20
#protocol pop3 {
#  pop3_uidl_format = %08Xu%08Xv
Notes on the above:
  • We'll setup letsencrypt certs later.
  • You should have certs generated automatically, if you want to learn more about handling them with correct file permissions and so on, refer to the dovecot wiki.
  • I commented out the last lines by hand.
A default install of dovecot sees many files placed inside the dovecot directory. Out of interest, I removed all of them except for the earlier generated dovecot-new.conf, which I renamed to dovecot.conf. Dovecot still started and remote connections to the server worked. Using "nmap localhost" I could verify that the listening ports were just the same. Therefore, I could verify that the other files were technically unnecessary for the pupose of this setup. However, to ensure your ease for future customisation, you'll want to leave those default files there.

In my version of the config, I am not using an include statement in dovecot.conf, so the conf.d files are not read. The dovecot documentation is really good, see
The default configuration starts from dovecot.conf, which contains an !include conf.d/*.conf statement to read the rest of the configuration. This split of configuration files isn't a requirement to use, and it doesn't really matter which .conf file you add any particular setting, just as long as it isn't overridden in another file. You can verify with doveconf -n that everything looks as you intended.
If you use systemd, you may encounter these messages:
# service dovecot start
Jun 14 22:09:56 mail dovecot[20409]: Error: systemd listens on port 143, but it's not configured in Dovecot. Closing.
Jun 14 22:09:56 mail dovecot: master: Error: systemd listens on port 143, but it's not configured in Dovecot. Closing.
Jun 14 22:09:56 mail dovecot[20409]: Error: systemd listens on port 143, but it's not configured in Dovecot. Closing.
Jun 14 22:09:56 mail dovecot: master: Error: systemd listens on port 143, but it's not configured in Dovecot. Closing.
Jun 14 22:09:56 mail dovecot: master: Dovecot v2.2.13 starting up for imap (core dumps disabled)
The messages are not actually something to worry about. Suggestions around the Internet say that they can be stopped as so:
# systemctl disable dovecot.socket
Removed symlink /etc/systemd/system/
I'm not sure whether that works. You might want to do some googling to understand more about systemd. For now, it's not important.

Troubleshooting Dovecot

Use "tail -vf /var/log/syslog" to see dovecot reporting IMAP authentication and connections.

There are further troubleshooting notes in the Webmail post (part 3) of this series.

Once again, the dovecot docs are really good!

No comments:

Post a Comment