Self-hosted emails with Docker-Mailserver

Self-hosted emails with Docker-Mailserver

Introduction

I'm obsessed with self hosting services. I started self hosting things about a year ago and ever since I have loved the idea of hosting my own email server, but I always thought that it would be far too complicated and I would be stuck with large email providers like Google or Microsoft.

Enter Docker-Mailserver.

Docker-Mailserver is a full-stack email server which includes SMTP, IMAP, LDAP, Anti-spam, and Anti-virus, all wrapped in an easily configurable Docker image.

Requirements

In order to get this running you'll need somewhere to host the email server, I am using a $6 Vultr VPS running Ubuntu Linux which is plenty of power for 1 person.

On the server, you will need to have docker installed (optionally docker-compose as well, makes installation a lot easier) and root access if you're using Uncomplicated Firewall (UFW).

Lastly, you will need a domain name and the ability to edit DNS zones in order to send and receive emails on your domain.

Getting started

Setup script

If anything during this setup is unclear, Docker-Mailserver have put together some great documentation to help you out. https://docker-mailserver.github.io/docker-mailserver/edge/

Start by creating a directory to work out of in your home directory and download the setup script that we'll use to interact with the Docker-Mailserver container.

mkdir docker-mailserver
cd docker-mailserver

wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/setup.sh

chmod a+x ./setup.sh

Next we'll run the setup script once so that the Docker image is pulled and saved to the server: ./setup.py help

Once the image has been pulled, you should see a printout on the screen from the setup script with some example commands. You will need to use this to interact with the Docker-Mailserver container for things like debugging, adding email accounts and configuring DKIM keys.

Docker compose

The docker-compose file below is what I am using in my setup; however, there is a sample file that can be used on the docker-mailserver website plus a lot of extra environment variables that aren't listed here which can be turned on.

services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    hostname: mail
    # Change this to your domain, it will be used for your email accounts.
    domainname: example.com
    container_name: mailserver
    ports:
      - "25:25"
      - "587:587"
      - "465:465"
      - "993:993"
      - "143:143"
    volumes:
      - maildata:/var/mail
      - mailstate:/var/mail-state
      - maillogs:/var/log/mail
      - ./config/:/tmp/docker-mailserver/
      - ./docker-data/certbot/certs:/etc/letsencrypt
    environment:
      - ENABLE_SPAMASSASSIN=1
      - SPAMASSASSIN_SPAM_TO_INBOX=1
      # Enable this if your server has more than 1GB of RAM
      - ENABLE_CLAMAV=0
      - ENABLE_FAIL2BAN=1
      - ENABLE_POSTGREY=1
      - ENABLE_SASLAUTHD=0
      - ONE_DIR=1
      - DMS_DEBUG=0
      - SSL_TYPE=letsencrypt
      # You may want to enable this: https://docker-mailserver.github.io/docker-mailserver/edge/config/environment/#spoof_protection
      # See step 8 below, which demonstrates setup with enabled/disabled
    SPOOF_PROTECTION:
      - SPOOF_PROTECTION=0
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    restart: always

volumes:
  maildata:
  mailstate:
  maillogs:

Make sure to read the comments within the Docker-compose file as there may be a few changes required for your setup.

Once you're happy with the configuration, startup the container with
docker-compose up -d. Make sure the container started correctly by running
docker logs mailserver.

Firewall / Port Forwarding

By default, allowing the required ports should be very simple but these steps may be slightly different depending on your setup.

For Vultr, there is no firewall configured behind the server by default so we simply need to run the following UFW commands on the server itself. If you prefer, you can disable UFW on the server and setup a firewall in the Vultr management interface instead.

ufw allow 25
ufw allow 587
ufw allow 465
ufw allow 143
ufw allow 993
ufw allow 80 		# I'll explain why shortly.

The ports above will remain the same for any firewall setup.

DNS

Now that we have a running container for our mailserver and we have allowed the required ports on our server, we're ready to enable our domain to send and receive emails.

You will need to create 2 kinds of records in order to get mail flow working, an MX record to direct the mail flow and an SPF record to validate where you're allowed to send emails from.

Your DNS records should look something like this:

mail      IN  A   *your-server-IP*

; mail-server for example.com
    3600  IN  MX  1  mail.example.com.

; Add SPF record
          IN TXT "v=spf1 mx ~all"

Inside your SPF record, you may want to replace 'mx' with/or add 'ip4:your-ip-address', especially if you have something like an SMTP relay.

We'll also need to generate DKIM keys and create a new DNS record for that. On your mailserver host, use the setup script to run ./setup.sh config dkim

If you have copied my setup, copy the content of the file config/opendkim/keys/example.com/mail.txt and add it as a DNS record like the MX and SPF records earlier

Example:

mail._domainkey IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; "          "p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgSvBJpS8a2FE2x9uwUCsNMiGUOckHQVJJQsnM3+TdWgVMUlGiCkizcZ6HODzNEzCvQxHf2Esz+kLumUBVg32lFha0UecfABD24tlLQqc449ROy70WLNe01cmzacZYc/ameV1YIzpo2xvN49ZK8bGnbzDiu2nSN5ASAexa9"
          "V/MSCOB5uZigfVe0XBycH3oCGGEN7QxvU1eZ3/ea/WpNzCFp89O9o96+4k5ySgB+zfgzk/iP50f5uwKboZZT0GhLGIjD0TOAZW5SJhg4KdEboFd06xYwe0v6Ns2HIoumEhk5w9KL8uF4SKtc8lrtafGD/XgNPsoVbzvTD365FGYt0bd8xPhctdZh99rX8SYuZUXmjKACRQ9ZjdFtb1OcCbb/jK"        "GAgZFLSD2qFvVOI3R0jJyFotIWOCjTqEJw9FAH8sEi75D8e1L/L2ZoJsinInkzroxSErqaDJ6nUn/D7+WfEDPIRdwIXL6PEY3rUtwikPvua6HhdiqxCTKvgZuQXMhShi0dTZpmNWe0pxoLOD+Wfadk2MF/9WHi+hJ8u5Hs6AqdxrZZNnMVScOrU2UlephG3FfMB+HNqZXFMCAwEAAQ==" )  ; 
          ----- (Edited) DKIM key mail for gardnr.dev

Lets Encrypt Certificate

This step is optional; however, it is highly recommended.

In the docker-compose file created earlier, we set the SSL_TYPE to letsencrypt and mounted ./docker-data/certbot/certs to /etc/letsencrypt. This was to setup an application called Certbot which will generate an SSL certificate for our domain automatically.

The certifcate should generate when you run the docker-compose file but if you're having trouble, the below command can be run to generate an SSL certificate in the same folder.

# Change `mail.example.com` below to your own FQDN.
# Requires access to port 80 from the internet, adjust your firewall if needed.
docker run --rm -it \
  -v "${PWD}/docker-data/certbot/certs/:/etc/letsencrypt/" \
  -v "${PWD}/docker-data/certbot/logs/:/var/log/letsencrypt/" \
  -p 80:80 \
  certbot/certbot certonly --standalone -d mail.example.com

This is why we allowed port 80 earlier

You will receive an email from letsencrypt after 30 days advising that your SSL certificate has expired so make sure you run the renew command every 30 days.

# This will need access to port 443 from the internet, adjust your firewall if needed.
docker run --rm -it \
  -v "${PWD}/docker-data/certbot/certs/:/etc/letsencrypt/" \
  -v "${PWD}/docker-data/certbot/logs/:/var/log/letsencrypt/" \
  -p 80:80 \
  -p 443:443 \
  certbot/certbot renew

Wrapping up

At this stage, the mailserver is completely setup. The last thing we need to do is create an email address using the setup script:

./setup.sh email add admin@example.com passwd123
./setup.sh alias add admin@example.com postmaster@example.com

Now start your container and you're done!

This guide won't cover setting up an email client so you can send/receive emails but I found eM Client (Link) to be a really nice alternative to for Outlook and it can be used completely free. eM Client is also very easy to configure as you just need to plug in your mailserver address and the secure SMTP & IMAP ports.

Website: https://gardnr.dev/
GitHub: https://github.com/Jay-Gardiner/

Docker-Mailserver: https://docker-mailserver.github.io/docker-mailserver/edge/
eM Client: https://www.emclient.com/