Since february I'm running a little server from my home network. I planned a while to run a mail server on it, but since it's behind a dynamic ip, no other server would accept outgoing mail from me. At the end of july the hoster ovh offered a very small but cheap server. Additionally I wanted to get away from all the mailhosters helping the NSA to spy. This server is not intended for servers with many users but is more for single users or small user groups. Therefore plain config files are used instead of a database.

When I was configuring the new server I decided to use scripts because of two reasons: First because I automatically have kind of documentation on what I have done and second because I very easily can set up new servers. Because I'm kind of a python fanboy and I'm not really into puppet or chef I decided to use ansible for this.

For the configuration I read a lot of tutorials and did the best I can, if you have improvements please just email me or make a pull request on github.


My code is of course kept in a git repository and you can find here. A short description of the structure of ansible playbooks:

  • host.ini: Contains all servers with parameters and to which groups they belong.
  • main.yml: Includes the other yaml files which define roles and such.
  • secure: All files that have to stay private (keys, passwd file...)
  • roles: Contains one directory per role. You can map hosts or groups to roles, so you can reuse the roles. In this article we only concentrate on the mailserver directory.

The mailserver directory contains tasks, here grouped by applications, templates and vars. The templates use the vars to generate the config files for the server. This part of the playbook is mainly based on the ansible repo of Fabien Dupont did a great job on this, I just added some minor tweaks and some documentation to the config file.

How to use


First of all you have to set the hostname of your server if you haven't done that already. Don't use the 'hostname'-command, this only changes the hostname temporarily and ansible doesn't use this temporary hostname. Just set it manually: Enter the hostname without domain into /etc/hosts and in /etc/hostnames enter the line hostname.domain.tld hostname

and then restart or use /etc/init.d/ start if youre on debian.. If your hoster supports it you should also set your reverse DNS entry to the same value.

Then you have to prepare the host.ini: Put every mailserver into the group 'mailservers'. If you want to relay your mail instead of sending them directly, put the relaying servers into the group 'secondarymx' and configure the according variables in roles/mailserver/vars/main.yml if they are the same for all servers or in host_vars/<hostname> if they differ per host.

Next you have to edit roles/mailserver/templates/etc_ssl_dovecot.cnf. It is used to generate the ssl certificate. Just read the comments in the file and you should pass easily.

Most important is to create the file dovecot.passwd in the folder secure: The easiest way to do this is to use doveadm pw. For this you have to install dovecot (or dovecot-core on Debian) on your desktop machine. For each account you have to insert one line looking like this:


If you don't want to install dovecot on your desktop only to generate some password hashes you can instead use a provisional dovecot.passwd where you use plain text passwords. This makes it easier to debug and you can run ansible one time, use the dovecot installation on the server to generate the password hashes, use them to make the dovecot.passwd on your local machine and run ansible again.

You should also adjust the variable 'mx_aliases' in roles/mailserver/vars/main.yml. It configures redirects from the first listed account to the second account. It is very useful to map the root account to your personal main account because you can not directly login as root via imap.

You should also go through the complete roles/mailserver/vars/main.yml and check if you want to adjust something.

For ansible to work you must only install python onto the server.


After you have configured everything as you wanted it's now time to roll that thing out.

ansible-playbook -i hosts.ini mailservers.yml --user <username> --ask-sudo-pass


Finally you can use some tools to test if your server is working properly, for example this one tests specifically , if your server is an open relay. Another one is this, which grades the overall security of your server.

Of course you can also use telnet or send some emails from, to and within your domain.

You can now also configure your DNS to contain a SPF record and the DKIM record if you use it.


Here I have listed some problems I have run into. They are mostly a bit stupid but maybe they are helpful for someone.

<date> babaco postfix/smtp[2175]: 0901EC0AA0: to=<a@b.c>, ... status=bounced (mail for b.c loops back to myself)

In my case just the wrong hostname was used in /etc/postfix/ Make sure you have set the hostname correct and maybe restart the server and run ansible once again.

<date> babaco postfix/smtp[30796]: connect to[]:10025: Connection refused

In my case clamAV wasn't running after the ansible-playbook, I had to start it manually.