This is the third section in the 4 part series of migrating my server
- Install and configure the host machine
- Install and configure a database and webserver
- Install and configure a mailserver - we are here
- Install and configure vaultwarden
- Tie everything back to 1. for backups, misc, etc
Dockerized mailserver
We will install a dockerized mailserver, a sort of all in one that will run a full fledged secure mail service. There are many containers that can perform this and on my previous servers I used iRedmail. The main issue with most containerized mail solutions is that it requires port 80 and 443 for various webmail and it is tied into various other services so its hard to remove, same for other parts of the service. I found and chose docker-mailserver and it pretty much did almost everything I needed and wanted.
Why docker-mailserver
- documentation is better than most other projects
- looks to be maintained and updated frequently
- does not need port 80 or 443
- comes with a very simple
setup.sh
that you can use to manage your mailboxes - configuration options are a plenty where you can configure what you need.
Install
I will assume that you configured your DNS correctly and created all the TXT and MX records. If not docker-mailserver
does have pretty decent docs about how to configure your DNS.
configure a system wide certificate
docker-maliserver
can use letsencrypt to generate its own certs but it requires port 80 and 443 since it uses the http-01
method to generate the cert. So instead I will use certbot in a container to generate my cert. My domains are hosted on namecheap
so I will use a namecheap plugin for certbot
to use dns-01
validation to create my domain and wildcard certs. I will create 1 cert for all of my domains and their wildcards.
- Create directories
# mkdir -p /opt/certbot/logs
- Create
/opt/config/namecheap.ini
certbot_dns_namecheap:dns_namecheap_username=namecheap.com-username certbot_dns_namecheap:dns_namecheap_api_key=namecheap.com-apitoken-generated-from-settings
- Generate certs - user the following to generate the certs
docker run -it --rm \ -v /opt/certbot:/etc/letsencrypt \ -v /opt/certbot/logs:/var/log/letsencrypt \ -v /opt/config/namecheap.ini:/namecheap.ini \ schubc/certbot-dns-namecheap certonly \ --non-interactive \ -a certbot-dns-namecheap:dns-namecheap \ --certbot-dns-namecheap:dns-namecheap-credentials=/namecheap.ini \ --agree-tos \ --email "your@email.address" \ -d domain1.com -d *.domain1.com -d domain2.com -d *.domain2.com
- Link certs to
/etc/pki
The above will create certs(symlinks) onto/opt/certbot/live/domain1.com
I will create symlinks to/etc/pki/tls
ln -s /opt/certbot/live/domain1.com/fullchain.pem /etc/pki/tls/certs/fullchain.pem ln -s /opt/certbot/live/domain1com/privkey.pem /etc/pki/tls/private/privkey.pem
- Create a renew script and bounce any services when the cert is renewed
Now we need a script to check and renew our certificates and restart any services likedocker-mailserver
whenever the cert renews. I created a script named/opt/bin/renew-certs.sh
#!/bin/sh # renew # need to run periodically # add to cron to run once a week # 10 3 * * 0 /opt/bin/renew-certs.sh WORKDIR=/opt/certbot # snag a copy of old fullchain mkdir ${WORKDIR}/tmp cp ${WORKDIR}/live/domain1.com/fullchain.pem ${WORKDIR}/tmp/fullchain.pem # run the renewal docker run -it --rm \ -v /opt/certbot:/etc/letsencrypt \ -v /opt/certbot/logs:/var/log/letsencrypt \ -v /opt/config/namecheap.ini:/namecheap.ini \ schubc/certbot-dns-namecheap renew # check for diff if diff -q "${WORKDIR}/tmp/fullchain.pem" "${WORKDIR}/live/domain1.com/fullchain.pem"; then # no difference logger "[DEBUG] cert did not change" else logger "[DEBUG] cert changed and will restart containers" # restart containers that use the cert docker restart mailserver fi # cleanup rm -rf ${WORKDIR}/tmp exit 0
If you have other services that uses the default certs you can add it to the script to be restarted.
- Create cronjob
# Every Sunday at 3:10 check for cert renewal 10 3 * * 0 /opt/bin/renew-certs.sh > /dev/null 2>&1
configure docker-mailserver
Now for the mail server
- Create directories
# mkdir -p /opt/mailserver
- Install
docker-mailserver
DMS_GITHUB_URL='https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master' wget "${DMS_GITHUB_URL}/docker-compose.yml" wget "${DMS_GITHUB_URL}/mailserver.env" wget "${DMS_GITHUB_URL}/setup.sh" chmod a+x ./setup.sh ./setup.sh help
- Add a user
./setup.sh email add
- Setup DKIM
$ ./setup.sh config dkim domain 'domain1.com,domain2.com`
- Configure - Edit
/opt/mailserver/mailserver.env
for your needs. My config looks like the following but its really up to you
OVERRIDE_HOSTNAME= DMS_DEBUG=0 SUPERVISOR_LOGLEVEL= ONE_DIR=1 POSTMASTER_ADDRESS=jlim@domain1.com ENABLE_UPDATE_CHECK=1 UPDATE_CHECK_INTERVAL=1d PERMIT_DOCKER=host NETWORK_INTERFACE= TLS_LEVEL= SPOOF_PROTECTION=1 ENABLE_SRS=1 ENABLE_POP3= ENABLE_CLAMAV=1 ENABLE_AMAVIS=1 AMAVIS_LOGLEVEL=0 ENABLE_FAIL2BAN=1 FAIL2BAN_BLOCKTYPE=drop ENABLE_MANAGESIEVE= POSTSCREEN_ACTION=enforce SMTP_ONLY= SSL_TYPE=manual SSL_CERT_PATH=/tmp/dms/custom-certs/live/domain1.com/fullchain.pem SSL_KEY_PATH=/tmp/dms/custom-certs/live/domain1.com/privkey.pem SSL_ALT_CERT_PATH= SSL_ALT_KEY_PATH= VIRUSMAILS_DELETE_DELAY= ENABLE_POSTFIX_VIRTUAL_TRANSPORT= POSTFIX_DAGENT=lmtp:unix:private/dovecot-lmtp POSTFIX_MAILBOX_SIZE_LIMIT= ENABLE_QUOTAS=0 POSTFIX_MESSAGE_SIZE_LIMIT= PFLOGSUMM_TRIGGER=logrotate PFLOGSUMM_RECIPIENT=jlim@domain1.com PFLOGSUMM_SENDER=postmaster@domain1.com LOGWATCH_INTERVAL=weekly LOGWATCH_RECIPIENT=jlim@domain1.com REPORT_RECIPIENT=1 REPORT_SENDER= REPORT_INTERVAL=daily POSTFIX_INET_PROTOCOLS=all ENABLE_SPAMASSASSIN=1 SPAMASSASSIN_SPAM_TO_INBOX=1 MOVE_SPAM_TO_JUNK=1 SA_TAG=2.0 SA_TAG2=6.31 SA_KILL=6.31 SA_SPAM_SUBJECT=***SPAM***** ENABLE_FETCHMAIL=0 FETCHMAIL_POLL=300 ENABLE_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_TLS= DOVECOT_USER_FILTER= DOVECOT_PASS_FILTER= DOVECOT_MAILBOX_FORMAT=maildir DOVECOT_AUTH_BIND= ENABLE_POSTGREY=1 POSTGREY_DELAY=300 POSTGREY_MAX_AGE=35 POSTGREY_TEXT="Delayed by Postgrey" POSTGREY_AUTO_WHITELIST_CLIENTS=5 ENABLE_SASLAUTHD=0 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= SASL_PASSWD= SASLAUTHD_LDAP_AUTH_METHOD= SASLAUTHD_LDAP_MECH= SRS_SENDER_CLASSES=envelope_sender SRS_EXCLUDE_DOMAINS= SRS_SECRET= DEFAULT_RELAY_HOST= RELAY_HOST= RELAY_PORT=25 RELAY_USER= RELAY_PASSWORD=
- Configure
/opt/mailserver/docker-compose.yml
- mine looks like
services: mailserver: image: docker.io/mailserver/docker-mailserver:latest container_name: mailserver # If the FQDN for your mail-server is only two labels (eg: example.com), # you can assign this entirely tohostname
and removedomainname
. hostname: mail domainname: domain1.com env_file: mailserver.env # More information about the mail-server ports: # https://docker-mailserver.github.io/docker-mailserver/edge/config/security/understanding-the-ports/ # To avoid conflicts with yaml base-60 float, DO NOT remove the quotation marks. ports: - "25:25" # SMTP (explicit TLS => STARTTLS) - "143:143" # IMAP4 (explicit TLS => STARTTLS) - "465:465" # ESMTP (implicit TLS) - "587:587" # ESMTP (explicit TLS => STARTTLS) - "993:993" # IMAP4 (implicit TLS) volumes: - ./docker-data/dms/mail-data/:/var/mail/ - ./docker-data/dms/mail-state/:/var/mail-state/ - ./docker-data/dms/mail-logs/:/var/log/mail/ - ./docker-data/dms/config/:/tmp/docker-mailserver/ - /opt/certbot:/tmp/dms/custom-certs/:ro - /etc/localtime:/etc/localtime:ro - /opt/temp:/temp/ restart: always stop_grace_period: 1m cap_add: - NET_ADMIN - NET_RAW - SYS_PTRACE
- Start container - this is the only containers that is not in systemd. Since its using docker-compose it will return when the host is rebooted.
$ cd /opt/mailserver $ docker-compose -f docker-compose.yml up -d # this will start the mailserver container with everything from docker-compose.yml $ # docker-compose -f docker-compose.yml down # this will take down the container and the network $ # docker-compose restart mailserver # this will restart the mailserver container
- Some tips
- You can view the mail logs via
docker logs -f mailserver
or going into the containerdocker exec -it mailserver bash
and tail -f /var/log/mail.log - On my host(Rocky) and the
mailserver
container I was unable to get fail2ban to work correctly in the container. I updated the iptables and ip6tables alternatives to get it working.# update-alternatives --all
and selectiptables-nft
and ip6tables-nft` - You can goto various mail server test sites to test your mail server and when I did this all the tests came out GREEN
- You can view the mail logs via
Please view Linux basic install – Migrated to a new server 1 of 4 about how to configure your host OS to relay mail via the container.