Backup MX Configuration for Mailcow – Don’t Miss an Email

As a sysadmin, setting up and maintaining a self-hosted mail server for your organization involves a lot of responsibility – but the old adage that “hosting your own email is not worth the trouble” couldn’t be further from the truth. That being said, end users treat email as a “utility” which means they expect their inbox to be available whenever they need it, and certainly to never miss an incoming email message. Email is the modern workplace’s most important communication tool, which means internal users at all levels of the organization, in addition to external stakeholders such as customers/clients, vendors/suppliers, and the government, expect a company’s email server to be reliable.

Although a properly configured Mailcow server should rarely experience downtime, planned maintenance (such as essential updates) can momentarily require Postfix, the service responsible for processing incoming email, to restart. Although all major email services (including Gmail, Outlook/Office 365, and corporate email servers) respect the RFC standard stating that outgoing email to a domain should be retried for 3 to 5 days if no MX servers can be reached, it may take hours for an outgoing mail server to retry.

This can be particularly inopportune for a time-sensitive email which you were expecting from an important client. Instead of relying on the sender’s mail server to re-attempt delivery, setting up a backup MX server with Mailcow means that incoming messages will be received, even when your primary Mailcow server is down. As soon as your primary Mailcow server comes back online, the backup Mailcow will deliver the queued messages to each recipient’s inbox.

This article addresses how to set up a backup MX server for a primary Mailcow instance, using a secondary Mailcow instance. It assumes you have provisioned a virtual server separate from your primary Mailcow instance, with the latest version of Docker and Docker Compose installed. For maximum redundancy and fault-tolerance, the secondary MX should reside on a virtual server in a different availability zone, or even geographical region from your primary MX.

The secondary Mailcow server should have a minimum of 2 GB RAM / 1 CPU, or the amount of resources provisioned for the primary Mailcow server (whichever is more). Realistically using a smaller amount of resources for the secondary Mailcow server could probably suffice, since users will not be accessing the SOGo groupware or IMAP/ActiveSync/CalDAV/CardDAV through the backup server.

The steps below assume that the primary Mailcow server is located at mail.example.com and the secondary Mailcow server is located at mailsec.example.com.

Befoer proceeding, the following DNS records should be creating on the DNS provider hosting your authoritative nameservers. Note that the priority of the MX record pointed at mailsec.example.com should be a greater number (20) than the MX record for mail.example.com (10). This tells other email servers that they should always attempt to deliver to the primary MX first.

111.111.111.111 should be the public IP address of the secondary Mailcow server.

mailsec.example.com. 300 IN A 111.111.111.111

example.com. 60 IN MX 20 mailsec.example.com.
example.com. 60 IN MX 10 mail.example.com.

sudo systemctl disable ufw
sudo systemctl stop ufw
apt update && apt upgrade -y
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd /opt/mailcow-dockerized

./generate_config.sh

Press enter to confirm the detected value '[value]' where applicable or enter a custom value.
Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname: mailsec.example.com
Timezone [Etc/UTC]:
Installed memory is <= 2.5 GiB. It is recommended to disable ClamAV to prevent out-of-memory situations. ClamAV can be re-enabled by setting SKIP_CLAMD=n in mailcow.conf. Do you want to disable ClamAV now? [Y/n] Y
Disabling Solr on low-memory system.

docker-compose pull
docker-compose up -d

Visit https://mailsec.example.com/ to access the mailcow UI control panel.

HTTPS not working? In http://mailsec.example.com/debug, check for error “Cannot validate hostnames, skipping Let’s Encrypt for 1 hour.” in Logs > ACME.

docker-compose restart acme-mailcow

If the certificate is obtained successfully, you should see “Certificate successfully deployed, removing backup, sleeping 1d” when you refresh http://mailsec.example.com/debug.

docker-compose restart nginx-mailcow

Then try visiting https://mailsec.example.com/ again.

If Mailcow is not force redirecting HTTP to HTTPS, you should configure that by editing /opt/mailcow-dockerized/mailcow.conf and ensure HTTP_BIND=0.0.0.0 Then edit /opt/mailcow-dockerized/data/conf/nginx/site.conf, and add this server block above the first instance server { appears in the nginx config file.

server {
listen 80 default_server;
listen [::]:80 default_server;
include /etc/nginx/conf.d/server_name.active;
if ( $request_uri ~* "%0A|%0D" ) { return 403; }
return 301 https://$host$uri$is_args$args;
}

Run docker-compose up -d and docker-compose restart nginx-mailcow.

Make sure you change the default mailcow UI admin password from admin / moohoo.

Once logged in, you are taken to the Configuration & Details > Access view. Under Edit Administrator Details, select the checkmark beside Username → admin and click Edit. Now in Password and Confirmation password (repeat), specify the password of your choice and click Save Changes.

From the top navigation bar, click Configuration and select Mail Setup.
You will be taken to the screen where you can add a mail receiving domain. Click Add domain.

In the modal window which appears, fill in the Domain and write a description of your choice. Not the domain of the Mailcow server, but the domain after the “@” portion of your email address.

Beside Backup MX options, select the checkbox for Relay this domain and Relay all recipients. Note “If you choose not to relay all recipients, you will need to add a (“blind”) mailbox for every single recipient that should be relayed.” Click Add domain and restart SOGo.

The setup of the backup MX server is complete.

Now sign in to the mailcow UI of your primary Mailcow server as an administrator, which might reside at mail.example.com. You will now whitelist the backup MX server to deliver held messages to your primary Mailcow server.

Once logged in, you are taken to the Configuration & Details > Access view. Select the Configuration tab. Scroll down until you see the Forwarding Hosts section and under Add forwarding host enter mailsec.example.com. In the Spam Filter dropdown, feel free to select Inactive as any incoming mail would have already been filtered by the secondary Mailcow server. Click Add.

There’s one final step before you can be confident that mail queued up by the backup MX (if the primary MX is down) will be delivered to users’ inboxes once the primary MX is restored.

From the DNS provider which hosts your domain’s authoritative nameservers, update your SPF record to allow your secondary MX to send emails on behalf of your domain. This prevents your primary Mailcow server from rejecting the forwarded emails based on the SPF settings.

We assume you already have a SPF record created when you setup your primary Mailcow server. Do not create an additional SPF record. Instead, add include:mailsec.example.com to the existing SPF record. The resulting SPF record should look something like this.

example.com. 300 IN TXT "v=spf1 mx include:mail.example.com include:mailsec.example.com ~all

If you wanted to test your backup MX server, you could temporarily shutdown your primary Mailcow server, send an email to one of your configured inboxes (from an outside provider), then switch the primary Mailcow server back on. The secondary Mailcow server should successfully deliver the messages that it received when the primary server was down.

After your primary Mailcow server is back up, if you want to manually process the queue on the backup MX server, you can login to the mailcow UI (of the primary server) as an administrator and select the Queue manager tab. There you will see a list of messages which were queued up while the primary MX server was down. To deliver the queued emails to the primary server’s inboxes, simply click the Flush queue button, which is the same as running the postqueue -f command against the Postfix server. In a few moments, the queued messages will be delivered to the recipients’ inboxes.