
28 Jan 2016
Easy private email hosting with dockermail
So you own a domain and would like to host your own email but the set-up is a massive pain?
No problem! There is a tool just for that: dockermail.
It's a modular email service in docker containers, which is very easy to configure.
In this post I will run you through setting up your very own email server from scratch.
Install
For this tutorial you will only need to have docker
and docker-compose
installed.
Head over to docker.com and follow the 'getting started' instructions on your platform. In my case I will be using Ubuntu Linux.
docker-compose is not essential but will make launching and linking containers a breeze.
Configuration
To be on the right side of SPAM filters we will be using DomainKeys Identified Mail (DKIM) signing, this will sign all outgoing mail with a secret key, which recipients can verify against a public one you will publish through your DNS records.
And to complete the circle, we will also filter incoming email for SPAM.
First let's create a couple of folders.
We will need a place for our email, you can let the container keep it in a volume, but for safe keeping and backup you should mount it to a host folder. In our case we will create a folder /opt/dockermail/mail
.
And finally for our settings create /opt/dockermail/settings
and open a terminal in there.
DKIM key
There is a script in the opendkim module of dockermail that will generate a DKIM key with a minimum of fuss.
It will fetch a copy of the opendkim image if you don't have it already, generate a key and dispose of the container when its done.
You can either download this script and run it locally, or you can run it straight from the web:
bash <(curl -s https://raw.githubusercontent.com/adaline/dockermail/master/opendkim/generate_key.sh) [your-domain.tld]
Just replace [your-domain.tld] with the domain you will be sending mail from.
For example let's use awesome-company.co.uk
:
$ bash <(curl -s https://raw.githubusercontent.com/adaline/dockermail/master/opendkim/generate_key.sh) awesome-company.co.uk
Generating keys for awesome-company.co.uk
Add a TXT domain record with key: "default._domainkey" and value:
---------
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwTDvwqhb9K0hEbyOBKc9/HE2q8Uv8ndMUW7PeQIepTUD23gWlXL+s4w0taS5BdLAq8DRe5BA7FoE0FbMk3fC7iq96rJrsiYeKED2tDjcbyTfZfhw/eLdEURFkb0fyMUuv73XACGvuVgdXXJMHdM4keu5Hn/uEAHa5UkzZZpUUwIDAQAB
---------
Printing a private key: awesome-company.co.uk.opendkim_key
You should now have a file awesome-company.co.uk.opendkim_key
in your settings folder.
Go to your domain name provider and add a TXT record with the key default._domainkey
and the long string you got from the command above as the value, in our case:
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwTDvwqhb9K0hEbyOBKc9/HE2q8Uv8ndMUW7PeQIepTUD23gWlXL+s4w0taS5BdLAq8DRe5BA7FoE0FbMk3fC7iq96rJrsiYeKED2tDjcbyTfZfhw/eLdEURFkb0fyMUuv73XACGvuVgdXXJMHdM4keu5Hn/uEAHa5UkzZZpUUwIDAQAB
Accounts
Both the email core module and the incoming SPAM filter use the same single settings file - config.json
, which looks like this:
{
"settings": {
"myhostname": ""
},
"domains": {
}
}
myhostname
under settings
should be the hostname of your mail server. In our example we will just use awesome-comapny.co.uk
but you may want to use mail.awesome-company.co.uk
if you have that DNS record set up, or perhaps even epic-mail-server.com
if you want a white-label email for multiple domains!
Remember to set the MX record for your domain to the same hostname.
Let's update our config.json
file:
{
"settings": {
"myhostname": "awesome-company.co.uk"
},
"domains": {
}
}
The domains object should list all the domains you want to process mail for, you can host mail for multiple domains but in our case we will just host one:
{
"settings": {
"myhostname": "awesome-company.co.uk"
},
"domains": {
"awesome-company.co.uk": [
]
}
}
Each domain can have multiple accounts, which are specified in the enclosing array, let's add info@awesome-company.co.uk
:
{
"settings": {
"myhostname": "awesome-company.co.uk"
},
"domains": {
"awesome-company.co.uk": [
{
"email": "info@awesome-company.co.uk"
}
]
}
}
We will need a password to let us send and receive mail, this should be in a Dovecot format.
You can use a plan text password, which looks like this: {PLAIN}SuperSecure123
but for better security we will generate a SHA512-CRYPT hash instead.
Here is another easy one-liner to do this:
docker run -it --rm adaline/dockermail-core doveadm pw -s SHA512-CRYPT
You will be asked to type in a new password twice and it will produce a hash in the correct format for you:
$ docker run -it --rm adaline/dockermail-core doveadm pw -s SHA512-CRYPT
Enter new password:
Retype new password:
{SHA512-CRYPT}$6$zpOUDQBwt1NXMFZp$t1oiUoDcoNKCgFz1atkWDGTjnL2c1vuShzrGFQta8xLlw2CEPwVDWl1NDHDPK7dYrOS.Le4TvKHiXcULGUKyM0
Let's add this password to our new account in config.json
:
{
"settings": {
"myhostname": "awesome-company.co.uk"
},
"domains": {
"awesome-company.co.uk": [
{
"email": "info@awesome-company.co.uk",
"password": "{SHA512-CRYPT}$6$zpOUDQBwt1NXMFZp$t1oiUoDcoNKCgFz1atkWDGTjnL2c1vuShzrGFQta8xLlw2CEPwVDWl1NDHDPK7dYrOS.Le4TvKHiXcULGUKyM0"
}
]
}
}
At this point you have everything you need to get started, but as a nice addition let's redirect mail sent to non-existent email addresses into our info@awesome-company.co.uk
mailbox. To do this we need to add a "catch all" alias, which is just an email address with no account, in our case - @awesome-company.co.uk
:
{
"settings": {
"myhostname": "awesome-company.co.uk"
},
"domains": {
"awesome-company.co.uk": [
{
"email": "info@awesome-company.co.uk",
"password": "{SHA512-CRYPT}$6$zpOUDQBwt1NXMFZp$t1oiUoDcoNKCgFz1atkWDGTjnL2c1vuShzrGFQta8xLlw2CEPwVDWl1NDHDPK7dYrOS.Le4TvKHiXcULGUKyM0",
"aliases": ["@awesome-company.co.uk"]
}
]
}
}
Save this as config.json
in your /opt/dockermail/settings/
folder.
That's it, we are done with configuration.
Launch
To launch and link the dockermail modules together we will use docker-compose utility you have installed earlier.
It takes a YAML file which will look like this:
core:
image: adaline/dockermail-core
ports:
- "25:25"
- "143:143"
- "587:587"
volumes:
- /opt/dockermail/settings:/mail_settings
- /opt/dockermail/mail:/vmail
links:
- opendkim
- amavis
opendkim:
image: adaline/dockermail-opendkim
volumes:
- /opt/dockermail/settings:/mail_settings
amavis:
image: adaline/dockermail-amavis
volumes:
- /opt/dockermail/settings:/mail_settings
Let's save this file in /opt/dockermail/settings/
as docker-compose.yml
.
To launch, simply run:
docker-compose -d -f /opt/dockermail/settings/docker-compose.yml up -d
Congrats, you should now have a running email server of your very own:
$ docker-compose -f /opt/dockermail/settings/docker-compose.yml up -d
Starting settings_opendkim_1...
Starting settings_amavis_1...
Starting settings_core_1...
Client setup
You will need to set up your email client with a shiny new account.
This will be an IMAP account, use your hostname for the server.
Your incoming (IMAP) port number is 143, use STARTTLS as connection security.
For outgoing (SMTP) port you can use ether the standard 25 or if your internet provider loves money more than they love you, use 587. Again connection security should be set to use STARTTLS.
You are done - time to send that all-important "Hello world" email!
Nice things to know
Although we have configured DKIM, there are a few more things you should add
to make your email stay clear of the SPAM folder.
There is a great service mail-tester.com, which will test your configuration and give you more info on what needs to be done.
To make sure your email comes back if your server is restarted, you should add
a startup script to your server's init system. Newer Ubuntu servers use systemd,
while older might use upstart - search the web on how to configure yours.
Add me on LinkedIn: Valentin Arkhipov
Follow me on Twitter: @webmadespecial
All blog posts