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.
Before we setup a mail server, make sure hostname
and hosts
already set.
If you are not sure please read this Initial Setup guide.
In this guide will choose /srv/
as path for Docker applications.
1. Deploy Docker-Mailer
We will setup a mailer server that support:
- SSL with Let's Encrypt
- Fail2Ban Protection
- Correct Timezone
- 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
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
As you can see from above,
- The container name is
mailserver
. So for the next, we will call it asmailserver
instead of Docker Mailserver. - 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
#!/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
0 1 * * * /usr/bin/sh /srv/mailserver/autorenewssl.sh >> /var/log/autorenewssl.log 2>&1
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
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.
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
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
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
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:
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
- 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.