Sign inSign up

michaelk/mailserver

By michaelk

Updated about 8 years ago

Mail server based on postfix, dovecot, …

Image
0

260

michaelk/mailserver repository overview

2017-08-26 -> 1.1 is ready ! :heart_eyes:

A new stable version is available (1.1-stable). Please see the list of changes here and the migration procedure here.

For the next 6 months, the latest docker tag will always point to 1.0 version to not break compatibility with older installations. After January 2018, those who have not yet migrated, will receive an error at the next update (docker pull) and will be prompted to update the mail server or to switch to the 1.0-legacy docker tag (not recommended).

Crafted with love by @hardware and all contributors :gift_heart:

hardware/mailserver

Build

Docker image

Simple and full-featured mail server as a set of multiple docker images includes :

  • Postfix : a full set smtp email server supporting custom rules
  • Dovecot : secure imap and pop3 email server
  • Rspamd : anti-spam filter with SPF, DKIM, DMARC, ARC, ratelimit and greylisting capabilities
  • Clamav : antivirus with automatic updates
  • Zeyple : automatic GPG encryption of all your e-mails
  • Sieve : email filtering (vacation auto-responder, auto-forward...etc)
  • Fetchmail : fetch e-mails from external IMAP/POP3 server into local mailbox
  • Rainloop : web based email client
  • Postfixadmin : web based administration interface
  • Unbound: recursive caching DNS resolver with DNSSEC support
  • 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, custom and self-signed certificates support
  • Supporting multiple virtual domains over PostgreSQL backend
  • Integration tests with Travis CI
  • Automated builds on DockerHub
System Requirements

Please check, if your system meets the following minimum system requirements :

TypeWithout ClamAVWith ClamAV
CPU1 GHz1 GHz
RAM1 GiB2 GiB
Disk5 GiB (without emails)5 GiB (without emails)
Systemx86_64x86_64
Prerequisites
Cleaning

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 interfering 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.

Ports

If you have a firewall, unblock the following ports, according to your needs :

ServiceSoftwareProtocolPort
SMTPPostfixTCP25
HTTPNginxTCP80
POP3DovecotTCP110
IMAPDovecotTCP143
HTTPSNginxTCP443
SMTPSPostfixTCP465
SubmissionPostfixTCP587
IMAPSDovecotTCP993
POP3SDovecotTCP995
ManageSieveDovecotTCP4190
DNS setup

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

Mandatory DNS records (A/MX) and reverse PTR :

A correct DNS setup is required, this step is very important.

HOSTNAMECLASS TYPEPRIORITYVALUE
mailINA/AAAAany1.2.3.4
@INMX10mail.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.

HOSTNAMECLASS TYPEPRIORITYVALUE
@INTXTany"v=spf1 a mx ip4:SERVER_IPV4 ~all"
mail._domainkeyINTXTany"v=DKIM1; k=rsa; p=YOUR DKIM Public Key"
_dmarcINTXTany"v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; 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/dkim/domain.tld/public.key

These DNS record will raise your trust reputation score and reduce abuse of your domain name. You can find more information here :

Some useful Thunderbird extensions :

Testing

You can audit your mailserver with the following assessment services :

Installation
1 - Pull the latest image from docker hub
# Pull from hub.docker.com
docker pull hardware/mailserver:1.1-stable # Get the stable version (v1.1-stable branch)
docker pull hardware/mailserver:1.1-latest # Get the latest version (master branch)

# or build it manually
docker build -t hardware/mailserver https://github.com/hardware/mailserver.git#v1.1-stable

:warning: latest docker tag points to a legacy version until january 2018 to not break the compatibility with old installations.

:bulb: 1.1-latest tag is the latest development build. These builds have been validated through the CI automation system but they are not meant for deployment in production.

:bulb: For security reasons, you should regularly update all of your docker images.

2 - Get the latest docker-compose.yml

Change your hostname and domain name, adapt to your needs : docker-compose.sample.yml

Run the stack :

docker-compose up -d
3 - Reverse proxy setup

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

Notice : if you plan to use Let's Encrypt as Certificate Authority; be sure to request them before with the XATAZ way.

4 - Postfixadmin installation

PostfixAdmin is a web based interface used to manage mailboxes, virtual domains and aliases.

5 - Rainloop installation (optional)

Rainloop is a simple, modern and fast webmail with Sieve scripts support (filters and vacation message), GPG and a modern user interface.

6 - Done, congratulation ! :tada:

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

[INFO] Let's encrypt live directory found
[INFO] Using /etc/letsencrypt/live/mail.domain.tld folder
[INFO] Creating DKIM keys for domain domain.tld
[INFO] Database hostname found in /etc/hosts
[INFO] Fetchmail forwarding is enabled.
[INFO] Automatic GPG encryption is enabled.
[INFO] ManageSieve protocol is enabled.
[INFO] POP3 protocol is enabled.
-------------------------------------------------------------------------------------
2017-08-26T11:06:58.885562+00:00 mail root: s6-supervise : spawning clamd process
2017-08-26T11:06:59.059077+00:00 mail root: s6-supervise : spawning freshclam process
2017-08-26T11:06:59.395214+00:00 mail root: s6-supervise : spawning rspamd process
2017-08-26T11:07:01.615597+00:00 mail root: s6-supervise : spawning unbound process
2017-08-26T11:07:01.870856+00:00 mail root: s6-supervise : spawning postfix process
2017-08-26T11:07:03.303536+00:00 mail root: s6-supervise : spawning dovecot process
...
Ansible Playbooks

logo

If you use Ansible, I recommend you to go to see @ksylvan playbooks here : https://github.com/ksylvan/docker-mail-server

Environment variables

:warning: Use only ASCII printable characters in environment variables : https://en.wikipedia.org/wiki/ASCII#Printable_characters

Github issue : https://github.com/hardware/mailserver/issues/118

VariableDescriptionTypeDefault value
VMAILUIDvmail user idoptional1024
VMAILGIDvmail group idoptional1024
VMAIL_SUBDIRIndividual mailbox' subdirectoryoptionalmail
OPENDKIM_KEY_LENGTHSize of your DKIM RSA key pairoptional1024
PASSWORD_SCHEMEPasswords encryption schemeoptionalSHA512-CRYPT
DBHOSTPostgreSQL instance ip/hostnameoptionalpostgresql
DBPORTPostgreSQL instance portoptional3306
DBUSERPostgreSQL database usernameoptionalpostfix
DBNAMEPostgreSQL database nameoptionalpostfix
DBPASSPostgreSQL database password or location of a file containing itrequirednull
REDIS_HOSTRedis instance ip/hostnameoptionalredis
REDIS_PORTRedis instance portoptional6379
REDIS_PASSRedis database password or location of a file containing itoptionalnull
REDIS_NUMBRedis database numberoptional0
RSPAMD_PASSWORDRspamd WebUI and controller password or location of a file containing itrequirednull
ADD_DOMAINSAdd additional domains to the mailserver separated by commas (needed for dkim keys etc.)optionalnull
RELAY_NETWORKSAdditional IPs or networks the mailserver relays without authenticationoptionalnull
DISABLE_RSPAMD_MODULEList of disabled modules separated by commasoptionalnull
DISABLE_CLAMAVDisable virus scanningoptionalfalse
DISABLE_SIEVEDisable ManageSieve protocoloptionalfalse
DISABLE_SIGNINGDisable DKIM/ARC signingoptionalfalse
DISABLE_GREYLISTINGDisable greylisting policyoptionalfalse
DISABLE_RATELIMITINGDisable ratelimiting policyoptionalfalse
DISABLE_DNS_RESOLVERDisable the local DNS resolveroptionalfalse
ENABLE_POP3Enable POP3 protocoloptionalfalse
ENABLE_FETCHMAILEnable fetchmail forwardingoptionalfalse
ENABLE_ENCRYPTIONEnable automatic GPG encryptionoptionalfalse
FETCHMAIL_INTERVALFetchmail polling intervaloptional10
RECIPIENT_DELIMITERRFC 5233 subaddress extension separator (single character only)optional+
Automatic GPG encryption of all your e-mails
How does it work ?

Zeyple catches email from the postfix queue, then encrypts it if a corresponding recipient's GPG public key is found. Finally, it puts it back into the queue.

zeyple

Enable automatic GPG encryption

:heavy_exclamation_mark: Please enable this option carefully and only if you know what you are doing.

Switch ENABLE_ENCRYPTION environment variable to true. The public keyring will be saved in /var/mail/zeyple/keys. Please don't change the default value of RECIPIENT_DELIMITER (default = "+"). If encryption is enabled with another delimiter, Zeyple could have an unpredictable behavior.

Import your public key

:warning: Make sure to send your public key on a gpg keyserver before to run the following command.

docker exec -ti mailserver encryption.sh import-key YOUR_KEY_ID
Import all recipients public keys

This command browses all /var/mail/vhosts/* domains directories and users subdirectories to find all the recipients addresses in the mailserver.

docker exec -ti mailserver encryption.sh import-all-keys
Specify another gpg keyserver
docker exec -ti mailserver encryption.sh import-key YOUR_KEY_ID hkp://pgp.mit.edu
docker exec -ti mailserver encryption.sh import-all-keys hkp://keys.gnupg.net
Run other GPG options

You can use all options of gpg command line except an already assigned parameter called --homedir.

docker exec -ti mailserver encryption.sh --list-keys
docker exec -ti mailserver encryption.sh --fingerprint
docker exec -ti mailserver encryption.sh --refresh-keys
docker exec -ti mailserver encryption.sh ...

Documentation : https://www.gnupg.org/documentation/manuals/gnupg/Operational-GPG-Commands.html

Relaying from other networks

The RELAY_NETWORKS is a space separated list of additional IP addresses and subnets (in CIDR notation) which the mailserver relays without authentication. Hostnames are possible, but generally disadvised. IPv6 addresses must be surrounded by square brackets. You can also specify an absolut path to a file with IPs and networks so you can keep it on a mounted volume. Note that the file is not monitored for changes.

You can use this variable to allow other local containers to relay via the mailserver. Typically you would set this to the IP range of the default docker bridge (172.17.0.0/16) or the default network of your compose. If you are unable to determine, you might just add all RFC 1918 addresses 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8

:warning: A value like 0.0.0.0/0 will turn your mailserver into an open relay!

SSL certificates
Let's Encrypt certificate authority

This mail setup uses 4 domain names that should be covered by your new certificate :

  • mail.domain.tld (mandatory)
  • postfixadmin.domain.tld (recommended)
  • spam.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 [email protected] \
    -d mail.domain.tld \ # <--- Mail FQDN is the first domain name, very important !
    -d webmail.domain.tld \
    -d postfixadmin.domain.tld \
    -d spam.domain.tld

docker-compose up -d
  • Important : When renewing certificates, you must restart affected containers.

  • :warning: 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}.

  • If you have generated a ECDSA certificate with a curve other than prime256v1 (NIST P-256), you need to change the Postfix TLS configuration because of a bug in OpenSSL 1.1.0. For example, if you use secp384r1 elliptic curve with your ECDSA certificate, change the tls_eecdh_strong_curve value :

# /mnt/docker/mail/postfix/custom.conf

tls_eecdh_strong_curve = secp384r1

Additional informations about this issue :

Another certificate authority (other than Let's Encrypt)

Place all your certificates in /mnt/docker/nginx/certs/live/mail.domain.tld

Required files in this folder :

FilenameDescription
privkey.pemPrivate key for the certificate
cert.pemServer certificate only
chain.pemRoot and intermediate certificates only, excluding server certificate
fullchain.pemAll 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.

Testing
# 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
Unbound DNS resolver

Unbound is a validating, recursive, and caching DNS resolver inside the container, you can control it with the remote server control utility.

Some examples :

# Display server status
docker exec -ti mailserver unbound-control status

# Print server statistics
docker exec -ti mailserver unbound-control stats_noreset

# Reload the server. This flushes the cache and reads the config file.
docker exec -ti mailserver unbound-control reload

Documentation : https://www.unbound.net/documentation/unbound-control.html

Persistent files and folders in /mnt/docker/mail Docker volume
/mnt/docker
└──mail
   ├──postfix
   |     custom.conf
   |  ├──spool (Postfix queues directory)
   │  │     defer
   │  │     flush
   │  │     hold
   │  │     maildrop
   │  │     ...
   ├──dovecot
   |     instances
   |     ssl-parameters.dat
   ├──clamav (ClamAV databases directory)
   │     bytecode.cvd
   │     daily.cld
   │     main.cvd
   ├──rspamd (Rspamd databases directory)
   │     rspamd.rrd
   |     stats.ucl
   ├──zeyple
   │  ├──keys (GPG public keyring)
   │  │     pubring.kbx
   │  │     trustdb.gpg
   │  │     ...
   ├──sieve
   │     default.sieve
   │     custom.sieve (custom default sieve rules for all users)
   ├──dkim
   │  ├──domain.tld
   │  │     private.key
   │  │     public.key
   ├──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)
Override postfix configuration

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 = [email protected]
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 = [email protected]
[INFO] Override : delay_warning_time = 2h
[INFO] Custom Postfix configuration file loaded
Email client settings :
  • IMAP/SMTP username : [email protected]
  • 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
Components
  • Postfix 3.1.4
  • Dovecot 2.2.27
  • Rspamd 1.6.5
  • Fetchmail 6.3.26
  • ClamAV 0.99.2
  • Zeyple 1.2.1
  • Unbound 1.6.0
  • s6 2.6.1.1
  • Rsyslog 8.24.0
  • ManageSieve server
Community projects
Donation

My Bitcoin address : 1LwRr6jvzPHnZsxjk6u3wcfP555ZeC47Tg

This address is signed cryptographically to prove that it belongs to me. https://keybase.io/hardware

Tag summary

Content type

Image

Digest

Size

125.4 MB

Last updated

about 8 years ago

docker pull michaelk/mailserver:postgresql