Go to file
2021-02-10 16:53:14 +01:00
.github Rename config.yaml to config.yml 2021-02-10 16:53:14 +01:00
config Fix shebangs 2021-01-02 14:49:35 +01:00
target follow up style enhancement 2021-02-09 12:12:36 +01:00
test Support extra user_attributes in accounts configuration (#1792) 2021-02-07 19:02:09 +01:00
.dockerignore Final Migration Step (#6) 2021-01-16 10:16:05 +01:00
.editorconfig Introducing the repository secret (#18) 2021-01-18 20:51:56 +01:00
.gitignore Merge pull request #1613 from martin-schulze-vireso/feature/extract_even_more_tests 2020-10-28 11:16:15 +01:00
.gitmodules update bats to latest version 2019-08-05 21:40:09 +02:00
CHANGELOG.md adjusting CHANGELOG and CONTRIBUTING 2021-02-01 18:49:58 +01:00
CODE_OF_CONDUCT.md Final Migration Step (#6) 2021-01-16 10:16:05 +01:00
compose.env Final Migration Step (#6) 2021-01-16 10:16:05 +01:00
CONTRIBUTING.md Add PR template (#1795) 2021-02-07 11:59:09 +01:00
docker-compose.yml Final Migration Step (#6) 2021-01-16 10:16:05 +01:00
Dockerfile enhancement for function _setup_postfix_sasl fixing #1796 & more 2021-02-07 18:11:33 +01:00
ENVIRONMENT.md Escaped the underscore of SCORE 2021-01-31 21:49:40 +01:00
LICENSE Final Migration Step (#6) 2021-01-16 10:16:05 +01:00
mailserver.env adding SUPERVISOR_LOGLEVEL to mailserver.env 2021-01-28 10:15:05 +01:00
Makefile Support extra user_attributes in accounts configuration (#1792) 2021-02-07 19:02:09 +01:00
README.md corrected setup.sh link in README 2021-02-06 18:01:56 +01:00
setup.sh Replace $_ in error trap (#1776) 2021-01-28 14:50:28 +01:00

Docker Mailserver

ci::status docker::pulls

A fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.). Only configuration files, no SQL database. Keep it simple and versioned. Easy to deploy and upgrade.

Why this image was created.

  1. Included Services
  2. Issues and Contributing
  3. Requirements
  4. Usage
  5. Examples
  6. Environment Variables
  7. Release Notes

Included Services

Requirements

Recommended:

  • 1 Core
  • 1-2GB RAM
  • Swap enabled for the container

Minimum:

  • 1 vCore
  • 512MB RAM

Note: You'll need to deactivate some services like ClamAV to be able to run on a host with 512MB of RAM. Even with 1G RAM you may run into problems without swap, see FAQ.

Usage

Available image sources / tags

The CI/CD workflows automatically build, test and push new images to container registries. Currently, the following registries are supported:

All workflows are using the tagging convention listed below. It is subsequently applied to all images pushed to supported container registries:

Event Ref Commit SHA Image Tags
push refs/heads/master cf20257 edge
push refs/heads/stable cf20257 stable
push tag refs/tags/1.2.3 ad132f5 1.2.3, 1.2, 1, latest
push tag refs/tags/v1.2.3 ad132f5 1.2.3, 1.2, 1, latest

Get the tools

Download the docker-compose.yml, compose.env, mailserver.env and the setup.sh files:

wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/setup.sh
wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/docker-compose.yml
wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/mailserver.env
wget -O .env https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/compose.env

chmod a+x ./setup.sh

Create a docker-compose environment

  • Install the latest docker-compose
  • Edit the files .env and mailserver.env to your liking:
    • .env contains the configuration for Docker Compose
    • mailserver.env contains the configuration for the mailserver container
    • these files supports only simple VAR=VAL
    • don't quote your values
    • variable substitution is not supported (e.g. OVERRIDE_HOSTNAME=$HOSTNAME.$DOMAINNAME).
  • Variables in .env are expanded in the docker-compose.yml file only and not in the container. The file mailserver.env serves this case where environment variables are used in the container.
  • If you want to use a bare domain (host name = domain name), see FAQ

Get up and running

If you'd like to use SELinux, add -Z to the variable SELINUX_LABEL in .env. If you want the volume bind mount to be shared among other containers switch -Z to -z

docker-compose up -d mail

# without SELinux
./setup.sh email add <user@domain> [<password>]
./setup.sh alias add postmaster@<domain> <user@domain>
./setup.sh config dkim

# with SELinux
./setup.sh -Z email add <user@domain> [<password>]
./setup.sh -Z alias add postmaster@<domain> <user@domain>
./setup.sh -Z config dkim

If you are using a LDAP setup the setup looks a bit different as you do not add user accounts directly. Therefore postfix doesn't know your domain(s) and you need to provide it when configuring dkim:

docker-compose up -d mail

./setup.sh config dkim <key-size> <domain.tld>[,<domain2.tld>]

Miscellaneous

DNS - DKIM

When keys are generated, you can configure your DNS server by just pasting the content of config/opendkim/keys/domain.tld/mail.txt to set up DKIM.

Custom user changes & patches

If you'd like to change, patch or alter files or behavior of docker-mailserver, you can use a script. Just place it the config/ folder that is created on startup and call it user-patches.sh. The setup is done like this:

# 1. Either create the config/ directory yourself
#    or let docker-mailserver create it on initial
#    startup
/where/docker-mailserver/resides/ $ mkdir config && cd config

# 2. Create the user-patches.sh script and make it
#    executable
/where/docker-mailserver/resides/config/ $ touch user-patches.sh
/where/docker-mailserver/resides/config/ $ chmod +x user-patches.sh

# 3. Edit it
/where/docker-mailserver/resides/config/ $ vi user-patches.sh
/where/docker-mailserver/resides/config/ $ cat user-patches.sh
#! /bin/bash

# ! THIS IS AN EXAMPLE !

# If you modify any supervisord configuration, make sure
# to run `supervisorctl update` and/or `supervisorctl reload` afterwards.

# shellcheck source=/dev/null
. /usr/local/bin/helper-functions.sh

_notify 'Applying user-patches'

if ! grep '192.168.0.1' /etc/hosts
then
  echo -e '192.168.0.1 some.domain.com' >> /etc/hosts
fi

And you're done. The user patches script runs right before starting daemons. That means, all the other configuration is in place, so the script can make final adjustments.

Supported Operating Systems

We are currently providing support for Linux. Windows is not supported and is known to cause problems. Similarly, macOS is not officially supported - but you may get it to work there. In the end, Linux should be your preferred operating system for this image, especially when using this mailserver in production.

Support for Multiple Domains

docker-mailserver supports multiple domains out of the box, so you can do this:

./setup.sh email add user1@docker.example.com
./setup.sh email add user1@mail.example.de
./setup.sh email add user1@server.example.org

Updating docker-mailserver

docker-compose down
docker pull docker.io/mailserver/docker-mailserver:<VERSION TAG>
docker-compose up -d mailserver

You're done! And don't forget to have a look at the remaining functions of the setup.sh script with ./setup.sh -h.

SPF/Forwarding Problems

If you got any problems with SPF and/or forwarding mails, give SRS a try. You enable SRS by setting ENABLE_SRS=1. See the variable description for further information.

Exposed ports

Protocol Opt-in Encryption ¹ Enforced Encryption Purpose
SMTP 25 N/A Transfer²
ESMTP 587 465³ Submission
POP3 110 995 Retrieval
IMAP4 143 993 Retrieval
  1. A connection may be secured over TLS when both ends support STARTTLS. On ports 110, 143 and 587, docker-mailserver will reject a connection that cannot be secured. Port 25 is required to support insecure connections.
  2. Receives email and filters for spam and viruses. For submitting outgoing mail you should prefer the submission ports(465, 587), which require authentication. Unless a relay host is configured, outgoing email will leave the server via port 25(thus outbound traffic must not be blocked by your provider or firewall).
  3. A submission port since 2018, RFC 8314. Originally a secure variant of port 25.

See the wiki for further details and best practice advice, especially regarding security concerns.

Examples

With Relevant Environmental Variables

This example provides you only with a basic example of what a minimal setup could look like. We strongly recommend that you go through the configuration file yourself and adjust everything to your needs. The default docker-compose.yml can be used for the purpose out-of-the-box, see the usage section.

version: '3.8'

services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    hostname: mail          # ${HOSTNAME}
    domainname: domain.com  # ${DOMAINNAME}
    container_name: mail    # ${CONTAINER_NAME}
    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"
    volumes:
      - maildata:/var/mail
      - mailstate:/var/mail-state
      - maillogs:/var/log/mail
      - ./config/:/tmp/docker-mailserver/
    environment:
      - ENABLE_SPAMASSASSIN=1
      - SPAMASSASSIN_SPAM_TO_INBOX=1
      - ENABLE_CLAMAV=1
      - ENABLE_FAIL2BAN=1
      - ENABLE_POSTGREY=1
      - ENABLE_SASLAUTHD=0
      - ONE_DIR=1
      - DMS_DEBUG=0
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    restart: always

volumes:
  maildata:
  mailstate:
  maillogs:

LDAP setup

version: '3.8'

services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    hostname: mail          # ${HOSTNAME}
    domainname: domain.com  # ${DOMAINNAME}
    container_name: mail    # ${CONTAINER_NAME}
    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"
    volumes:
      - maildata:/var/mail
      - mailstate:/var/mail-state
      - maillogs:/var/log/mail
      - ./config/:/tmp/docker-mailserver/
    environment:
      - ENABLE_SPAMASSASSIN=1
      - SPAMASSASSIN_SPAM_TO_INBOX=1
      - ENABLE_CLAMAV=1
      - ENABLE_FAIL2BAN=1
      - ENABLE_POSTGREY=1
      - ONE_DIR=1
      - DMS_DEBUG=0
      - ENABLE_LDAP=1
      - LDAP_SERVER_HOST=ldap # your ldap container/IP/ServerName
      - LDAP_SEARCH_BASE=ou=people,dc=localhost,dc=localdomain
      - LDAP_BIND_DN=cn=admin,dc=localhost,dc=localdomain
      - LDAP_BIND_PW=admin
      - LDAP_QUERY_FILTER_USER=(&(mail=%s)(mailEnabled=TRUE))
      - LDAP_QUERY_FILTER_GROUP=(&(mailGroupMember=%s)(mailEnabled=TRUE))
      - LDAP_QUERY_FILTER_ALIAS=(|(&(mailAlias=%s)(objectClass=PostfixBookMailForward))(&(mailAlias=%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE)))
      - LDAP_QUERY_FILTER_DOMAIN=(|(&(mail=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailGroupMember=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailalias=*@%s)(objectClass=PostfixBookMailForward)))
      - DOVECOT_PASS_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
      - DOVECOT_USER_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
      - ENABLE_SASLAUTHD=1
      - SASLAUTHD_MECHANISMS=ldap
      - SASLAUTHD_LDAP_SERVER=ldap
      - SASLAUTHD_LDAP_BIND_DN=cn=admin,dc=localhost,dc=localdomain
      - SASLAUTHD_LDAP_PASSWORD=admin
      - SASLAUTHD_LDAP_SEARCH_BASE=ou=people,dc=localhost,dc=localdomain
      - SASLAUTHD_LDAP_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%U))
      - POSTMASTER_ADDRESS=postmaster@localhost.localdomain
      - POSTFIX_MESSAGE_SIZE_LIMIT=100000000
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    restart: always

volumes:
  maildata:
  mailstate:
  maillogs: