hardware/mailserver is a simple and full-featured mail server suite based on open source software as a set of multiple docker images including :
- Postfix : a full set smtp email server supporting custom rules
- Dovecot : secure imap and pop3 email server
- Amavis : content filter implementing decoding, processing and checking e-mails
- Spamassassin : anti-spam filter
- Clamav : antivirus with automatic updates
- OpenDKIM : implementation of DKIM (Domain Keys Identified Mail)
- OpenDMARC : implementation of DMARC (Domain-based Message Authentication, Reporting & Conformance)
- Sieve : email filtering (vacation auto-responder, auto-forward...etc)
- Fetchmail : fetch e-mails from external IMAP/POP3 server into local mailbox
- Postgrey : greylisting policy server
- Gross : greylisting of suspicious sources
- Rainloop : web based email client
- Postfixadmin : web based administration interface
- NSD : authoritative DNS server with DNSSEC support
- Nginx : web server with HTTP/2 and TLS 1.3 (DRAFT), statically linked against BoringSSL
- SSL : lets encrypt and self-signed certificates support
- Supporting multiple virtual domains over MySQL backend
- Integration tests with Travis CI
- Automated builds on DockerHub
Please check, if your system meets the following minimum system requirements :
Type | Without ClamAV | With ClamAV |
---|---|---|
CPU | 1 GHz | 1 GHz |
RAM | 500 MiB | 1 GiB |
Disk | 5 GiB (without emails) | 5 GiB (without emails) |
System | x86_64 | x86_64 |
Please remove any web server and mail services running on your server. I recommend using a clean installation of your prefered distro. If you are using Debian, remember to remove the default MTA Exim4 :
# apt-get purge exim4*
Also make sure that no other application is interferring with mail server configuration :
# netstat -tulpn | grep -E -w '25|80|110|143|443|465|587|993|995|4190'
If this command returns any results please remove or stop the application running on that port.
If you have a firewall, unblock the following ports, according to your needs :
Service | Software | Protocol | Port |
---|---|---|---|
SMTP | Postfix | TCP | 25 |
HTTP | Nginx | TCP | 80 |
POP3 | Dovecot | TCP | 110 |
IMAP | Dovecot | TCP | 143 |
HTTPS | Nginx | TCP | 443 |
SMTPS | Postfix | TCP | 465 |
Submission | Postfix | TCP | 587 |
IMAPS | Dovecot | TCP | 993 |
POP3S | Dovecot | TCP | 995 |
ManageSieve | Dovecot | TCP | 4190 |
I recommend you to use hardware/nsd-dnssec as an authoritative name server with DNSSEC capabilities. NSD is an authoritative only, high performance, simple and open source name server. This docker image is really easy to use.
How to setup : NSD initial configuration
A correct DNS setup is required, this step is very important.
HOSTNAME | CLASS | TYPE | PRIORITY | VALUE |
---|---|---|---|---|
IN | A/AAAA | any | 1.2.3.4 | |
@ | IN | MX | 10 | mail.domain.tld. |
Make sure that the PTR record of your IP matches the FQDN of your mailserver host. This record is usually set in your web hosting interface.
DKIM, SPF and DMARC are recommended to build a good reputation score.
HOSTNAME | CLASS | TYPE | PRIORITY | VALUE |
---|---|---|---|---|
@ | IN | TXT | any | "v=spf1 a mx ip4:SERVER_IPV4 ~all" |
mail._domainkey | IN | TXT | any | "v=DKIM1; k=rsa; p=YOUR DKIM Public Key" |
_dmarc | IN | TXT | any | "v=DMARC1; p=reject; rua=mailto:postmaster@domain.tld; ruf=mailto:admin@domain.tld; fo=0; adkim=s; aspf=s; pct=100; rf=afrf; sp=reject" |
Note: The DKIM public key will be available on host after the container startup :
/mnt/docker/mail/opendkim/domain.tld/mail.txt
These DNS record will raise your trust reputation score and reduce abuse of your domain name. You can find more information here :
You can audit your mailserver with the following assessment services :
# Pull from hub.docker.com :
docker pull hardware/mailserver
# or build it manually :
docker build -t hardware/mailserver https://github.com/hardware/mailserver.git#master
For security reasons, you should regularly update the mail setup and docker images.
Change your hostname and domain name, adapt to your needs : docker-compose.sample.yml
Run the stack :
mv docker-compose.sample.yml docker-compose.yml
docker-compose -f docker-compose.yml up -d
I recommend you to use wonderfall/boring-nginx as a reverse proxy. Nginx is statically linked against BoringSSL, with embedded Brotli support, TLS 1.3, X25519, HTTP/2 and hardening standards.
More information here : Reverse proxy configuration
PostfixAdmin is a web based interface used to manage mailboxes, virtual domains and aliases.
- Docker image : https://github.com/hardware/postfixadmin
- How to setup : Postfixadmin initial configuration
Rainloop is a simple, modern and fast webmail with Sieve scripts support (filters and vacation message), GPG and a modern user interface.
- Docker image : https://github.com/hardware/rainloop
- How to setup : Rainloop initial configuration
At first launch, the container takes few minutes to generate SSL certificates (if needed), Diffie-Hellman parameters, DKIM keypair and update clamav database, all of this takes some time (2/3 minutes), be patient...
This image comes with a snake-oil self-signed certificate, please use your own trusted certificates. See below for configuration.
You can check the startup logs with this command :
docker logs -f mailserver
Github issue : hardware#118
Variable | Description | Type | Default value |
---|---|---|---|
VMAILUID | vmail user id | optional | 1024 |
VMAILGID | vmail group id | optional | 1024 |
VMAIL_SUBDIR | Individual mailbox' subdirectory | optional | |
OPENDKIM_KEY_LENGTH | Size of your DKIM RSA key pair | optional | 2048 |
DBHOST | MariaDB instance ip/hostname | optional | mariadb |
DBPORT | MariaDB instance port | optional | 3306 |
DBUSER | MariaDB database username | optional | postfix |
DBNAME | MariaDB database name | optional | postfix |
DBPASS | MariaDB database password | required | null |
ADD_DOMAINS | Add additional domains to the mailserver separated by commas (needed for dkim keys etc.) | optional | null |
DISABLE_CLAMAV | Disable virus scanning | optional | false |
DISABLE_SPAMASSASSIN | Disable SPAM checking | optional | false |
DISABLE_SIEVE | Disable ManageSieve protocol | optional | false |
GREYLISTING | Enable greylisting policy server | optional | off |
ENABLE_POP3 | Enable POP3 protocol | optional | false |
ENABLE_FETCHMAIL | Enable fetchmail forwarding | optional | false |
FETCHMAIL_INTERVAL | Fetchmail polling interval | optional | 10 |
RECIPIENT_DELIMITER | RFC 5233 subaddress extension separator (single character only) | optional | + |
- If DISABLE_CLAMAV and DISABLE_SPAMASSASSIN are both set to true, Amavis is also completely disabled.
- The supported values for GREYLISTING are
off
,gross
orpostgrey
. Gross is a more advanced greylisting server which blocks only hosts with a bad DNSBL reputation. - Currently, only a single RECIPIENT_DELIMITER is supported. Support for multiple delimiters will arrive with Dovecot v2.3.
- FETCHMAIL_INTERVAL must be a number between 1 and 59 minutes.
This mail setup uses 3 domain names that should be covered by your new certificate :
- mail.domain.tld (mandatory)
- postfixadmin.domain.tld (recommended)
- webmail.domain.tld (optional)
To use the Let's Encrypt certificates, you can setup your docker-compose.yml
like this :
mailserver:
image: hardware/mailserver
volumes:
- /mnt/docker/nginx/certs:/etc/letsencrypt
...
nginx:
image: wonderfall/boring-nginx
volumes:
- /mnt/docker/nginx/certs:/certs
...
And request the certificate with xataz/letsencrypt or cerbot :
docker-compose stop nginx
docker run -it --rm \
-v /mnt/docker/nginx/certs:/etc/letsencrypt \
-p 80:80 -p 443:443 \
xataz/letsencrypt \
certonly --standalone \
--rsa-key-size 4096 \
--agree-tos \
-m contact@domain.tld \
-d mail.domain.tld \ # <--- Mail FQDN is the first domain name, very important !
-d webmail.domain.tld \
-d postfixadmin.domain.tld
docker-compose up -d
-
Important : When renewing certificates, you must restart affected containers.
-
β οΈ The common name of your ssl certifcate MUST be the same as your server's FQDN (for example, let's encrypt live subfolder name must be equal to domainname & hostname values of docker-compose file). Don't forget to add your FQDN in command above in first position. -
If you do not use let's encrypt, a default self-signed certificate (RSA 4096 bits SHA2) is generated here :
/mnt/docker/mail/ssl/selfsigned/{cert.pem, privkey.pem}
.
Place all your certificates in /mnt/docker/nginx/certs/live/mail.domain.tld
Required files in this folder :
Filename | Description |
---|---|
privkey.pem | Private key for the certificate |
cert.pem | Server certificate only |
chain.pem | Root and intermediate certificates only, excluding server certificate |
fullchain.pem | All certificates, including server certificate. This is concatenation of cert.pem and chain.pem |
Then mount the volume like this :
mailserver:
image: hardware/mailserver
volumes:
- /mnt/docker/nginx/certs:/etc/letsencrypt
...
You must restart affected containers.
# IMAP STARTTLS - 143 port (IMAP)
openssl s_client -connect mail.domain.tld:143 -starttls imap -tlsextdebug
# SMTP STARTTLS - 587 port (Submission)
openssl s_client -connect mail.domain.tld:587 -starttls smtp -tlsextdebug
# IMAP SSL/TLS - 993 port (IMAPS)
openssl s_client -connect mail.domain.tld:993 -tlsextdebug
/mnt/docker
βββmail
βββpostfix
β custom.conf
βββpostgrey
β postgrey.db
β ...
βββgross
β grossd.state
βββsieve
β default.sieve
β default.svbin
βββopendkim
β βββdomain.tld
β β mail.private
β β mail.txt
βββssl
β βββdhparams
β β dh512.pem
β β dh2048.pem
β βββlive (Let's Encrypt or other CA)
β β βββmail.domain.tld
β β β privkey.pem
β β β cert.pem
β β β chain.pem
β β β fullchain.pem
β βββselfsigned (Auto-generated if no certificate found)
β β cert.pem
β β privkey.pem
βββvhosts
β βββdomain.tld
β β βββuser
β β β .dovecot.sieve -> sieve/rainloop.user.sieve
β β β .dovecot.svbin
β β β βββmail
β β β β βββ.Archive
β β β β βββ.Drafts
β β β β βββ.Sent
β β β β βββ.Spam
β β β β βββ.Trash
β β β β βββcur
β β β β βββnew
β β β β ...
β β β βββsieve
β β β β rainloop.user.sieve (if using rainloop webmail)
Postfix default configuration can be overrided providing a custom configuration file at postfix format. This can be used to also add configuration that are not in default configuration. Postfix documentation remains the best place to find configuration options.
Each line in the provided file will be loaded into Postfix. Create a new file here /mnt/docker/mail/postfix/custom.conf
and add your custom options inside.
Example :
# /mnt/docker/mail/postfix/custom.conf
smtpd_banner = $myhostname ESMTP MyGreatMailServer
inet_protocols = ipv4
delay_notice_recipient = admin@domain.tld
delay_warning_time = 2h
docker logs -f mailserver
[INFO] Override : smtpd_banner = $myhostname ESMTP MyGreatMailServer
[INFO] Override : inet_protocols = ipv4
[INFO] Override : delay_notice_recipient = postmaster@domain.tld
[INFO] Override : delay_warning_time = 2h
[INFO] Custom Postfix configuration file loaded
- IMAP/SMTP username : user@domain.tld
- Incoming IMAP server : mail.domain.tld (your FQDN)
- Outgoing SMTP server : mail.domain.tld (your FQDN)
- IMAP port : 993
- SMTP port : 587
- IMAP Encryption protocol : SSL/TLS
- SMTP Encryption protocol : STARTTLS
- Postfix 2.11.3
- Dovecot 2.2.13
- OpenDKIM 2.9.2
- OpenDMARC 1.3.0
- Spamassassin 3.4.0
- Postgrey 1.35
- Fetchmail 6.3.26
- ClamAV 0.98.7
- Amavisd-new 2.10.1
- Amavisd-milter 1.5.0
- Supervisor 3.0r1
- Rsyslog 8.4.2
- ManageSieve server
- Use Rspamd/Rmilter instead of Spamassassin, Amavis, OpenDKIM and OpenDKIM
- ClueGetter integration
- Fork this repository
- Create a new feature branch for a new functionality or bugfix
- Code...
- Add integration tests in test/tests.bats
- Use
make
to build image locally and run tests - Document your improvements
- Commit your changes
- Push your code and open a new pull request
- Use issues for any questions