Docker-Compose setup for running a mailserver with Traefik as a reverse proxy.
Warning
This repository is a work in progress and might not be fully functional. Please use it with caution and report any issues you encounter or suggestions you have.
Important
The following setup expects you to have a working Traefik setup. You should also have setup the mailserver with the default configuration before using this setup. In case you haven't configured anything yet, you can use the provided files in this repository.
- Docker Mailserver + Traefik
- Table of Contents
- Overview
- Prerequisites
- Setup
- Test your setup
mailsetup.sh- License
- References
This setup uses Traefik as a reverse proxy and Docker Mailserver as the mailserver. The mailserver is configured to use Roundcube as the webmail client.
Roundcube is a modern webmail client that is easy to use and has a lot of features, but this is optional and can be removed if you want to use a different webmail client.
Note
In case you don't have a running traefik setup, you need to setup Traefik in the traefik directory. I recommend you to have a look at the setup of wollomatic/traefik-hardened. The configuration is also being used in this repository.
- Running Traefik setup with certificate generation over LetsEncrypt (otherwise you can use the provided
traefikdirectory in this repository) - You need a domain that you can use for the mailserver
- You need to have access to the DNS settings of the domain to set the correct records
This part will guide you through the setup of the mailserver and Traefik. It will show how to configure running instances of Traefik and the mailserver.
You can also clone this repository and use the given files in case you haven't running anything yet.
We need to add the following ports to the Traefik configuration to route the mailserver traffic:
Mailserver Ports
| Port | Type | Usage |
|---|---|---|
| 25 | SMTP | Used for sending emails |
| 465 | SMTP/SSL | Used for sending emails securely over SSL |
| 587 | SMTP/TLS | Used for sending emails securely over TLS |
| 993 | IMAP/SSL | Used for accessing emails over IMAP securely |
| 4190 | Sieve | Used for managing email filters |
Edit the traefik/docker-compose.yaml file:
traefik:
# Remaining configuration
ports:
- "10080:80"
- "10443:443"
+ - "25:25"
+ - "465:465"
+ - "587:587"
+ - "993:993"
+ - "4190:4190"Edit the your traefik configuration file (in this repo it's traefik/config/traefik.yaml):
entryPoints:
web:
address: ':10080' # will be routed to port 80, see docker-compose.yaml
http:
redirections: # redirect entire entrypoint to https
entryPoint:
to: ':443'
scheme: https
websecure:
address: ':10443' # will be routed to port 443, see docker-compose.yaml
http3:
advertisedPort: 443
+ smtp:
+ address: ':25'
+ smtp-ssl:
+ address: ':465'
+ smtp-tls:
+ address: ":587"
+ imap-ssl:
+ address: ':993'
+ sieve:
+ address: ':4190'That's it for the Traefik part. Now we can move on to the mailserver setup.
Important
You have to change the domain example.invalid to your domain in the following steps.
For the mailserver setup we're going to start with the docker-compose.yaml file.
Edit the mailserver/docker-compose.yaml file:
mailserver:
image: mailserver/docker-mailserver:latest
restart: unless-stopped
volumes:
+ - ../traefik/config/acme.json:/etc/traefik/acme.json:ro
+ hostname: mail
+ domainname: example.invalid
- ports:
- - "25:25"
- - "465:465"
- - "587:587"
- - "993:993"
- - "4190:4190"
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.mailserver.entrypoints=websecure"
+ - "traefik.http.routers.mailserver.rule=Host(`mail.example.invalid`)"
+ - "traefik.http.routers.mailserver.tls=true"
+ - "traefik.http.routers.mailserver.tls.certresolver=default"
+ - "traefik.http.routers.mailserver.middlewares=secHeaders@file"
+ - "traefik.http.routers.mailserver.service=noop@internal"
+ - "traefik.tcp.routers.smtp.rule=HostSNI(`*`)"
+ - "traefik.tcp.routers.smtp.entrypoints=smtp"
+ - "traefik.tcp.routers.smtp.service=smtp"
+ - "traefik.tcp.services.smtp.loadbalancer.server.port=25"
+ - "traefik.tcp.services.smtp.loadbalancer.proxyProtocol.version=1"
+ - "traefik.tcp.routers.smtp-ssl.rule=HostSNI(`*`)"
+ - "traefik.tcp.routers.smtp-ssl.entrypoints=smtp-ssl"
+ - "traefik.tcp.routers.smtp-ssl.tls.passthrough=true"
+ - "traefik.tcp.routers.smtp-ssl.service=smtp-ssl"
+ - "traefik.tcp.services.smtp-ssl.loadbalancer.server.port=465"
+ - "traefik.tcp.services.smtp-ssl.loadbalancer.proxyProtocol.version=1"
+ - "traefik.tcp.routers.smtp-tls.rule=HostSNI(`*`)"
+ - "traefik.tcp.routers.smtp-tls.entrypoints=smtp-tls"
+ - "traefik.tcp.routers.smtp-tls=true"
+ - "traefik.tcp.routers.smtp-tls.service=smtp-tls"
+ - "traefik.tcp.services.smtp-tls.loadbalancer.server.port=587"
+ - "traefik.tcp.services.smtp-tls.loadbalancer.proxyProtocol.version=1"
+ - "traefik.tcp.routers.imap-ssl.rule=HostSNI(`*`)"
+ - "traefik.tcp.routers.imap-ssl.entrypoints=imap-ssl"
+ - "traefik.tcp.routers.imap-ssl.service=imap-ssl"
+ - "traefik.tcp.routers.imap-ssl.tls.passthrough=true"
+ - "traefik.tcp.services.imap-ssl.loadbalancer.server.port=10993"
+ - "traefik.tcp.services.imap-ssl.loadbalancer.proxyProtocol.version=2"
+ - "traefik.tcp.routers.sieve.rule=HostSNI(`*`)"
+ - "traefik.tcp.routers.sieve.entrypoints=sieve"
+ - "traefik.tcp.routers.sieve.service=sieve"
+ - "traefik.tcp.services.sieve.loadbalancer.server.port=4190"
environment:
+ - "PERMIT_DOCKER=host"
+ - "SSL_TYPE=letsencrypt"
+ - "SSL_DOMAIN=example.invalid"
+ networks:
+ - traefik-servicenet-
Removal of ports - We don't need to expose the ports anymore, as Traefik will handle the routing
-
Labels - We're adding the Traefik labels to the mailserver container
-
Environment - We're setting the
SSL_DOMAINto the domain you're using for the mailserver and theSSL_TYPEtoletsencryptto use Let's Encrypt for the SSL certificates -
Environment - We're setting the
PERMIT_DOCKERtohostto allow the mailserver to communicate with the host -
Networks - We're adding the
traefiknetwork to the mailserver container to make it accessible to Traefik -
Certificate Generation - Mailserver must have a valid certificate for the domain in order to work properly.
- Traefik will generate certificates for the domain and store them in the
traefik/config/acme/acme.jsonfile. - The mailserver will use the certificates from the
acme.jsonfile to secure the connections.
- Traefik will generate certificates for the domain and store them in the
After the initial start of the mailserver, you can access the configuration files in the mailserver/config directory
You have to edit the following files:
postscreen_upstream_proxy_protocol = haproxy
smtpd_sasl_auth_enable = yes
smtpd_tls_auth_only = no
smtptd_sasl_auth_enable - Enable SASL authentication for the SMTP server
smtptd_tls_auth_only - Allow non-TLS connections for the SMTP server (might work also with yes, didn't test it)
submission/inet/smtpd_upstream_proxy_protocol=haproxy
smtps/inet/smtpd_upstream_proxy_protocol=haproxy
haproxy_trusted_networks = <TRAEFIK_SERVICENET_IP>/16
haproxy_timeout = 3 secs
service imap-login {
inet_listener imaps {
haproxy = yes
ssl = yes
port = 10993
}
}
Add the IP of the traefik-servicenet network to the haproxy_trusted_networks variable to allow the Dovecot server to communicate with Traefik over the network.
You can find the IP of the network by running docker network inspect traefik-servicenet
You need to add the following DNS records to your domain:
Mailserver DNS Records
| Type | Name | Value |
|---|---|---|
| A | mail.example.invalid | <YOUR_SERVER_IP> |
| MX | example.invalid | mail.example.invalid |
| TXT | mail._domainkey | v=DKIM1; k=rsa; p=<DKIM_PUBLIC_KEY> |
| TXT | _dmarc.example.invalid | v=DMARC1; p=none; rua=mailto: [email protected]; ruf=mailto: [email protected]; fo=1 |
| TXT | _spf.example.invalid | v=spf1 mx -all |
| PTR | <REVERSED_IP>.in-addr.arpa | mail.example.invalid |
You will get the DKIM public key from the mailserver/config/opendkim/keys/<YOUR_DOMAIN>/mail.txt file the initial start and setup of DKIM. Copy the contents and remove the quotes and the mail._domainkey IN TXT (" part.
After editing it should look like this:
v=DKIM1; h=sha256; k=rsa; p=Dmdklfi3o489DJKDdloeu4397dnDFJRdkejnslsdfllsdf343499834...After setup, you can test the mailserver by sending an email to the domain and checking if it arrives in the mailbox.
One useful tool for testing the mailserver is MX Toolbox. It will give you a set of tools to test the mailserver configuration.
- MX Lookup - Enter the domain and it will show you the MX records of the domain
- Test Email Server - Enter the domain and it will test the mailserver configuration
- DKIM Lookup - Enter the domain and it will show you the DKIM records of the domain
- SPF Lookup - Enter the domain and it will show you the SPF records of the domain
- DMARC Lookup - Enter the domain and it will show you the DMARC records of the domain
Tip
It's also worth checking your domain to see if it's blacklisted. You can do this by entering the domain in the Blacklist Check tool.
There are plenty of other tools on the website that can help you test your mailserver configuration.
Note
The script is just a small wrapper around the setup.sh from Docker Mailserver
I've created a script that will simplify the usage of the setup.sh from Docker Mailserver. It will allow you to run the setup commands inside the mailserver container without the need to type the docker compose exex mailserver all the time.
You can use it like this:
./mailsetup.sh <command>More details for usage with setup.sh at https://docker-mailserver.github.io/docker-mailserver/edge/config/setup.sh/
This project is licensed under the MIT License - see the LICENSE file for details.
- wollomatic/traefik-hardened - Traefik setup
- docker-mailserver/docker-mailserver - Docker Mailserver
- Mailsever behind Proxy - Docker Mailserver behind a proxy setup