Skip to main content
Version: 1.1.0

VII. Setup Mailserver

In this guide, we will setup Mailserver containerized inside docker. I choose Docker Mailserver because it's a production-ready fullstack but simple containerized mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.). Only configuration files, no SQL database. Keep it simple and versioned. Easy to deploy and upgrade.

info

Before we setup a mail server, make sure hostname and hosts already set.
If you are not sure please read this Initial Setup guide.

Docker Application Path

In this guide will choose /srv/ as path for Docker applications.

1. Deploy Docker-Mailer

note

We will setup a mailer server that support:

  1. SSL with Let's Encrypt
  2. Fail2Ban Protection
  3. Correct Timezone
  4. DKIM, DMARC and SPF

a. Create a directory

mkdir /srv/mailserver/

Then go to its directory

cd /srv/mailserver/

b. Create Docker Compose

nano docker-compose.yml

Then paste this

Opened file: /srv/mailserver/docker-compose.yml
services:
mailserver:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
container_name: mailserver
# Provide the FQDN of your mail server here (Your DNS MX record should point to this value)
hostname: mail.yourdomain.com
ports:
- "25:25" # SMTP (explicit TLS => STARTTLS)
- "143:143" # IMAP4 (explicit TLS => STARTTLS)
- "465:465" # ESMTP (implicit TLS)
- "587:587" # ESMTP (explicit TLS => STARTTLS)
- "993:993" # IMAP4 (implicit TLS)
volumes:
- ./docker-data/dms/mail-data/:/var/mail/
- ./docker-data/dms/mail-state/:/var/mail-state/
- ./docker-data/dms/mail-logs/:/var/log/mail/
- ./docker-data/dms/config/:/tmp/docker-mailserver/
- ./docker-data/certbot/certs/:/etc/letsencrypt
- /etc/localtime:/etc/localtime:ro
environment:
# Brute Force Protection
- ENABLE_FAIL2BAN=1
# Using letsencrypt for SSL/TLS certificates:
- SSL_TYPE=letsencrypt
# Allow sending emails from other docker containers:
# Beware creating an Open Relay: https://docker-mailserver.github.io/docker-mailserver/latest/config/environment/#permit_docker
- PERMIT_DOCKER=network
# Mail spoofing denied: https://docker-mailserver.github.io/docker-mailserver/latest/config/environment/#spoof_protection
- SPOOF_PROTECTION=1
# Supporting MTA-STS for outbound mail: https://docker-mailserver.github.io/docker-mailserver/latest/config/best-practices/mta-sts/
- ENABLE_MTA_STS=1
# Spam messages will be delivered to the Junk mailbox.
- MOVE_SPAM_TO_JUNK=1
# Set Timezone
- TZ=Europe/London
cap_add:
- NET_ADMIN # For Fail2Ban to work
restart: always
note

As you can see from above,

  1. The container name is mailserver. So for the next, we will call it as mailserver instead of Docker Mailserver.
  2. Don't forget to adjust the timezone, date time on mailer is very important.

c. Deploy Mailserver

Now deploy the Docker Mailserver

docker compose up -d

d. Try to see the logs

docker logs mailserver -f

2. Adjusting Firewall

We have to open the ports for mailer.

ufw allow 25/tcp && ufw allow 143/tcp && ufw allow 465/tcp && ufw allow 587/tcp && ufw allow 993/tcp

3. Configure SSL

a. Getting a Certificate

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.yourdomain.com

Done, now your mail server already support SSL.

b. Make it Automatically Renew

We have to create a bash script and make it execute scheduled with Cronjob.

Still on directory /srv/mailserver/.
Create a new file autorenewssl.sh.

nano autorenewssl.sh

Then paste this

Opened file: /srv/mailserver/autorenewssl.sh
#!/bin/sh
cd /srv/mailserver/
systemctl stop nginx
docker run --rm \
-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
systemctl start nginx

Then save it by press ctrl+x then press y and enter.

Now give an executable permission on it.

chmod +x autorenewssl.sh

Make it auto renew with Cronjob

crontab -e
output
0 1 * * * /usr/bin/sh /srv/mailserver/autorenewssl.sh >> /var/log/autorenewssl.log 2>&1
info
0 1 * * * /usr/bin/sh /srv/mailserver/autorenewssl.sh >> /var/log/autorenewssl.log 2>&1

Explanation:

  • Cronjob will check and auto renew the certificate for every day at 01.00 AM.
  • Cronjob will log any output at /var/log/autorenewssl.log
tip

If this is the first time you're setting the cronjob, you can test it by running this command.

env -i /bin/sh /srv/mailserver/autorenewssl.sh

4. Setup Fail2Ban

We don't need to setup Fail2Ban on email, because it was already did automatically from docker-compose.yml.
So here is the way to manage it.

a. See All Banned IP

docker exec mailserver setup fail2ban

b. Manage a Banned IP

docker exec mailserver setup fail2ban [<ban|unban> <IP>]

c. View the Fail2Ban Log

docker exec mailserver setup fail2ban log

d. Prevent container from self banned (optional)

Get self IP address and Gateway mailserver

docker inspect -f '{{range.NetworkSettings.Networks}}{{.Gateway}} {{.IPAddress}}{{end}}' mailserver

You will see the output of ip address.

example output
172.18.0.1 172.18.0.2

Then edit the jail.local fail2ban

docker exec -it mailserver nano /etc/fail2ban/jail.local

Look for ignoreip then modify it like this

/etc/fail2ban/jail.local
ignoreip = 127.0.0.1/8 172.18.0.1 172.18.0.2

Save it by press ctrl+x then press y and enter.

Now restart the mail server

docker restart mailserver

5. Create Email Account

a. Create a default email

We will use this email for setup DMARC later.

docker exec mailserver setup email add [email protected]

Then you will asked to input it password.

b. Create no_reply email

docker exec mailserver setup email add [email protected]

We will use [email protected] for OpenSSO later.

6. Setup DKIM

When you deploy this Docker Mailer, you have already got the DKIM generated by default with keysize 2048.

Now we have to regenerate it again and make the keysize lower.

a. Go to the mailserver container

docker exec -it mailserver bash 

b. Delete current DKIM

rm -rf /tmp/docker-mailserver/opendkim

Now exit from mailserver container.

exit

c. Generate new DKIM

Now we generate new DKIM with keysize 1024

docker exec -it mailserver setup config dkim keysize 1024 domain 'yourdomain.com'

Now restart the mailserver.
Make sure you still at directory /src/mailserver/.

docker compose restart

After restarting DMS, outgoing mail will now be signed with your new DKIM key(s) 🎉

Now you have a new generated DKIM.
It is located at /srv/mailserver/docker-data/dms/config/opendkim/keys/yourdomain.com/.

Now view it

cat /srv/mailserver/docker-data/dms/config/opendkim/yourdomain.com/mail.txt
Output
mail._domainkey IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsDYT31TLY8vfXEzT2CnQ3/SBf8krZFtZgkdbeEUbfvnCc64vsplACJnAjfKUx7QgVyf134hdhFy8bdJe2tzbe2dyNJ8AX/jSDDoFD+ocXqo6uNZLD+4xi0/xiHdv8yWeB7KUbzi0/u2nJWFAzGyZdR3i7O8FwTfTx1v+IJFHitwIDAQAB" ) ; ----- DKIM key mail for yourdomain.com

d. Add it in your DNS Cloudflare.

Type: TXT
Name: mail._domainkey
Proxy: DNS Only
TTL: 3600 / 1hr
Content:

v=DKIM1; h=sha256; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsDYT31TLY8vfXEzT2CnQ3/SBf8krZFtZgkdbeEUbfvnCc64vsplACJnAjfKUx7QgVyf134hdhFy8bdJe2tzbe2dyNJ8AX/jSDDoFD+ocXqo6uNZLD+4xi0/xiHdv8yWeB7KUbzi0/u2nJWFAzGyZdR3i7O8FwTfTx1v+IJFHitwIDAQAB
NOTE

Make sure you remove any double quotes and concat it carefully like the example above.
Because it could lead invalid signature if you miss about this.

7. Setup DMARC

Go to your clouflare and then add this in DNS section.
Type: TXT
Name: _dmarc
Proxy: DNS Only
TTL: 3600 / 1hr
Content:

v=DMARC1; p=reject; sp=reject; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; rua=mailto:[email protected]; ruf=mailto:[email protected]

Done.

8. Setup SPF

Go to your clouflare and then add this in DNS section.
Type: TXT
Name: yourdomain.com
Proxy: DNS Only
TTL: 3600 / 1hr
Content:

v=spf1 mx include:_spf.google.com ~all

Done.

9. Test your email

We have already setup the mail server. There is no web email client in this server.
So you need an email client software like Mozilla Thunderbird.

Here is the information detail about your email server.

Username : [email protected]
Password : [yourpassword]

IMAP Server : mail.yourdomain.com
IMAP Port : 143
Connection : STARTTLS

SMTP Server : mail.yourdomain.com
SMTP Port : 587
Connection : STARTTLS

10. Test the security

We already setup the basic security DKIm, DMARC and SPF.
Now you can test it using website:

congratulations

Now you already have the secured mail server.

11. Uninstall Completely

If you has been failed to configure the Mailserver or just in case want to completely uninstall Mailserver.

a. Remove Mailserver Service

Go to the mailserver directory

cd /srv/mailserver/

Take down, remove the service and delete its volume on docker.

docker compose down --volumes
info
  • This only remove the mailserver service and remove all its data.
  • This won't uninstall your docker system.

b. Delete its directory

Go up directory.

cd ..

Delete mailserver directory.

rm -rf mailserver

c. Verify the service

To make sure it has been removed.

docker container ls -a

Make sure there is no container name mailserver on the list.

Done.