Skip to content

mailserver

Handout

caddy tls cert

this cert is only for fqdn `mail..

extend compose.yaml under environment:

- SSL_TYPE=letsencrypt

extend caddyfile to generate cert:

mail.<domain>.<tld> {
    tls {
        key_type rsa2048
    }
}

mount certs into mailserver:

volumes:
- /mnt/raid/docker/volumes/caddy-data/_data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.<domain.tld>/mail.<domain.tld>.crt:/etc/letsencrypt/live/mail.<domain.tld>/fullchain.pem
- /mnt/raid/docker/volumes/caddy-data/_data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.<domain.tld>/mail.<domain.tld>.key:/etc/letsencrypt/live/mail.<domain.tld>/privkey.pem

ready to run

compose.yaml (click to expand)
services:
    mailserver:
        image: ghcr.io/docker-mailserver/docker-mailserver:latest
        restart: unless-stopped
        container_name: mailserver
        hostname: mail.<domain.tld>
        networks:
        - mailnet
        ports:
        - "25:25" ## SMTP
        - "587:587" ## ESMTP
        - "993:993" ## IMAP4
        - "11334:11334" ## RSPAMD WEBGUI
        environment:
        - LOG_LEVEL=info ## `error`, `warn`, `info`, `debug` and `trace`.
        - POSTMASTER_ADDRESS=postmaster@<domain.tld>
        - ENABLE_UPDATE_CHECK=1
        - UPDATE_CHECK_INTERVAL=1d
        - PERMIT_DOCKER=none
        - TZ=Europe/Zurich
        - NETWORK_INTERFACE= # **empty** => eth0
        - TLS_LEVEL=modern
        - SPOOF_PROTECTION=1
        - ENABLE_SRS=0
        - ENABLE_OPENDKIM=0 ## disable if ENABLE_RSPAWD=1
        - ENABLE_OPENDMARC=0 ## disable if ENABLE_RSPAWD=1
        - ENABLE_POLICYD_SPF=0 ## disable if ENABLE_RSPAWD=1
        - ENABLE_POP3=0
        - ENABLE_IMAP=1
        - ENABLE_CLAMAV=1
        - ENABLE_RSPAMD=1
        - ENABLE_RSPAMD_REDIS=1
        - RSPAMD_LEARN=0 ## maybe turning on if much spam
        - RSPAMD_CHECK_AUTHENTICATED=0
        - RSPAMD_GREYLISTING=1
        - RSPAMD_HFILTER=1
        - RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE=6
        - RSPAMD_NEURAL=0
        - ENABLE_AMAVIS=0 ## disable if ENABLE_RSPAWD=1
        - AMAVIS_LOGLEVEL=0
        - ENABLE_DNSBL=0
        - ENABLE_FAIL2BAN=1 ## uncomment cap_add if using
        - FAIL2BAN_BLOCKTYPE=drop
        - ENABLE_MANAGESIEVE=0
        - POSTSCREEN_ACTION=enforce
        - SMTP_ONLY=0
        - SSL_TYPE=letsencrypt
        - VIRUSMAILS_DELETE_DELAY=7 
        - POSTFIX_DAGENT= ## empty => `lmtp:unix:/var/run/dovecot/lmtp` (default, configured in Postfix main.cf)
        - POSTFIX_MAILBOX_SIZE_LIMIT=0 ## unlimited
        - ENABLE_QUOTAS=1
        - POSTFIX_MESSAGE_SIZE_LIMIT= ## empty => 10240000 (~10 MB)
        - CLAMAV_MESSAGE_SIZE_LIMIT= ## empty => 25M (25 MB)
        - PFLOGSUMM_TRIGGER=logrotate ## empty => no report; daily_cron => daily report; logrotate => full report as LOGROTATE_INTERVAL
        - PFLOGSUMM_RECIPIENT= ## empty => Use POSTMASTER_ADDRESS
        - PFLOGSUMM_SENDER= ## empty => use REPORT_SENDER
        - LOGWATCH_INTERVAL=daily ## emtpy => no report; daily => daily, weekly => weekly
        - LOGWATCH_RECIPIENT= ## empty => Use REPORT_RECIPIENT or POSTMASTER_ADDRESS
        - LOGWATCH_SENDER= ## empty => Use REPORT_SENDER
        - REPORT_RECIPIENT= ## emtpy => ${POSTMASTER_ADDRESS}
        - REPORT_SENDER= ## empty => mailserver-report@${DOMAINNAME}
        - LOGROTATE_INTERVAL=weekly ## weekly, daily and monthly
        - LOGROTATE_COUNT=4 ## defines how many log files are kept by logrorate
        - POSTFIX_REJECT_UNKNOWN_CLIENT_HOSTNAME=0
        - POSTFIX_INET_PROTOCOLS=ipv4 ## choose TCP/IP protocols for postfix to use
        - ENABLE_MTA_STS=0
        - DOVECOT_INET_PROTOCOLS=ipv4
        ## SPAMASSASSIN
        - ENABLE_SPAMASSASSIN=0 ## disable if ENABLE_RSPAWD=1
        - ENABLE_SPAMASSASSIN_KAM=0
        - SPAMASSASSIN_SPAM_TO_INBOX=1
        - MOVE_SPAM_TO_JUNK=1
        - MARK_SPAM_AS_READ=0
        - SA_TAG=2.0
        - SA_TAG2=6.31
        - SA_KILL=10.0
        ## FETCHMAIL
        - ENABLE_FETCHMAIL=0
        - FETCHMAIL_POLL=300
        - FETCHMAIL_PARALLEL=0
        - ENABLE_GETMAIL=0
        - GETMAIL_POLL=5
        ## OAUTH2
        - ENABLE_OAUTH2= ## empty => OAUTH2 authentication is disabled
        - OAUTH2_INTROSPECTION_URL=
        - SPAM_SUBJECT= ## optional if MOVE_SPAM_TO_JUNK=0
        - MOVE_SPAM_TO_JUNK=
        - MARK_SPAM_AS_READ=
        ## LDAP
        - LDAP_START_TLS=
        - LDAP_SERVER_HOST=
        - LDAP_SEARCH_BASE=
        - LDAP_BIND_DN=
        - LDAP_BIND_PW=
        - LDAP_QUERY_FILTER_USER=
        - LDAP_QUERY_FILTER_GROUP=
        - LDAP_QUERY_FILTER_ALIAS=
        - LDAP_QUERY_FILTER_DOMAIN=
        ## DOVECOT
        - DOVECOT_TLS=
        - DOVECOT_USER_FILTER=
        - DOVECOT_PASS_FILTER=
        - DOVECOT_MAILBOX_FORMAT=maildir
        - DOVECOT_AUTH_BIND=
        ## POSTGREY
        - ENABLE_POSTGREY=0 ## disable if RSPAMD_GREYLISTING=1
        - POSTGREY_DELAY=300
        - POSTGREY_MAX_AGE=35
        - POSTGREY_TEXT="Delayed by Postgrey"
        - POSTGREY_AUTO_WHITELIST_CLIENTS=5
        ## SASL
        - SASLAUTHD_MECHANISMS=
        - SASLAUTHD_MECH_OPTIONS=
        - SASLAUTHD_LDAP_SERVER=
        - SASLAUTHD_LDAP_BIND_DN=
        - SASLAUTHD_LDAP_PASSWORD=
        - SASLAUTHD_LDAP_SEARCH_BASE=
        - SASLAUTHD_LDAP_FILTER=
        - SASLAUTHD_LDAP_START_TLS=
        - SASLAUTHD_LDAP_TLS_CHECK_PEER=
        - SASLAUTHD_LDAP_TLS_CACERT_FILE=
        - SASLAUTHD_LDAP_TLS_CACERT_DIR=
        - SASLAUTHD_LDAP_PASSWORD_ATTR=
        - SASLAUTHD_LDAP_AUTH_METHOD=
        - SASLAUTHD_LDAP_MECH=
            ## SRS
        - SRS_SENDER_CLASSES=envelope_sender
        - SRS_EXCLUDE_DOMAINS=
        - SRS_SECRET=
            ## RELAY
        - DEFAULT_RELAY_HOST=
        - RELAY_HOST=
        - RELAY_PORT=25
        - RELAY_USER=
        - RELAY_PASSWORD=
        volumes:
        - dms-data:/var/mail/
        - dms-state:/var/mail-state/
        - dms-logs:/var/log/mail/
        - dms-config:/tmp/docker-mailserver/
        - /mnt/raid/docker/volumes/caddy-data/_data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.<domain.tld>/mail.<domain.tld>.crt:/etc/letsencrypt/live/mail.<domain.tld>/fullchain.pem
        - /mnt/raid/docker/volumes/caddy-data/_data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.<domain.tld>/mail.<domain.tld>.key:/etc/letsencrypt/live/mail.<domain.tld>/privkey.pem
        stop_grace_period: 1m
        # Uncomment if using `ENABLE_FAIL2BAN=1`:
         cap_add:
            - NET_ADMIN
        healthcheck:
        test: "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"
        timeout: 3s
        retries: 0


    networks:
        mailnet:
            external: true

    volumes:
        dms-data:
            external: true
        dms-state:
            external: true
        dms-logs:
            external: true
        dms-config:
            external: true

get help about setup

docker exec -it mailserver setup help

generate mail

docker exec -it mailserver setup email add <random>@<domain.tld>

Info

first mail has to be created within 2min after container start otherwise container will restart

add alias for postmaster

docker exec -it mailserver setup alias add postmaster@<domain.tld> <random>@<domain.tld>

generate dkim key for dns record

get help about dkim

docker exec -it mailserver setup config dkim help

docker exec -it mailserver setup config dkim domain <domain.tld>

Note

default keysize is 2048

Tip

specify domain from beginning so multiple domains are supported right away and rspamd is also thankful

u will get log output with your key and add it as dns txt record

mail._domainkey.<domain>.<tld>
and

"v=DKIM1; k=rsa; p=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLE"

add dmarc txt record

dmarc generator

_dmarc.<domain>.<tld>
and
"v=DMARC1; p=none; rua=mailto:postmaster@<domain>.<tld>; ruf=mailto:postmaster@<domain>.<tld>; sp=none; ri=86400"

add spf txt record

spf generator

"v=spf1 mx ~all"

add rDNS

use static ip with your provider and set rDNS at your provider

dig -x <staticip>
output: mail.<domain>.<tld>

catchall

add this to ~/docker/volumes/dms-config/_data/postfix-virtual.cf

@<domain.tld> <mail>@<domain.tld>

no container restart required after change

fail2ban

extend compose.yaml

environment: 
- ENABLE_FAIL2BAN=1

cap_add:
    - NET_ADMIN

create fail2ban-fail2ban.cf and fail2ban-jail.cf inside ~/dms-config/_data/ for customrules and reload container to get them copied inside container.

template:

fail2ban-fail2ban.cf

fail2ban-jail.cf

docker exec mailserver setup fail2ban status
docker exec mailserver setup fail2ban log

setup rspamd webgui

its enabled by default on port 11334 but password has to be generated

docker exec -it mailserver rspamadm pw

cd ~/docker/volumes/dms-config/_data/rspamd/
touch custom-commands.conf
and put this command into conf

set-option-for-controller password <passwordhas>

access it locally

http://<serverip>:11334/

setup roundcubemail

roundcubemail dockerimage works without any need to connect to a mailserver database. just define imap- and smtp-settings and use login-screen with mail credentials from mailaccount on mailserver.

compose.yaml (click to expand)

roundcubemail: image: roundcube/roundcubemail:latest container_name: roundcubemail restart: unless-stopped networks: - caddynet volumes: - rcm-frontend:/var/www/html - rcm-backend:/var/roundcube/db environment: - ROUNDCUBEMAIL_DB_TYPE=sqlite - ROUNDCUBEMAIL_SKIN=elastic - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://mail.. ## use ssl for ssl - ROUNDCUBEMAIL_DEFAULT_PORT=993 - ROUNDCUBEMAIL_SMTP_SERVER=tls://mail.. ## use tls for startls - ROUNDCUBEMAIL_SMTP_PORT=587

test

use online tools to check if dkim, dmarc, spf and headers are correct