Setup mailcow with Let’s Encrypt

A while back, while searching for a good mail server suite I came across mailcow which was built based on the following open source software:

  • Postfix
  • Dovecot
  • Nginx/Apache2
  • Spamassassin
  • ClamAV
  • MariaDB/MySQL
  • OpenDKIM
  • Roundcube
  • SabreDAV

Given that the suite looked promising and that the screenshots convinced me that it had a modern interface I decided to use it so I setup a virtual box aimed to run the mail server only. The mail server worked flawlessly and I couldn’t ask for much more from an open source system, except maybe replacing the self signed SSL certificate with a free alternative such as Let’s Encrypt.

So last night after seeing the new version release announcement I decided to  give it a go, upgrade mailcow and also replace the self signed certificate. The upgrade went smooth, but the built in Let’s Encrypt script didn’t work simply because the A records for the domains associated with the mail server were pointing to a different IP where their websites were hosted. Therefore I could only generate Let’s Encrypt for the server hostname, which is pretty much what I wanted to do.

Because I use Debian and mailcow is configured with Nginx I pulled the SSL certificate from Let’s Encrypt using certbot and the instructions for getting the Let’s Encrypt certificates with the use of certbot can be found here.

Once the certificates are generated you can find them in the /etc/letsencrypt/live/ directory. (replace with your own)

Now we have the certificates, but we must tell Postfix, Dovecot and Nginx about it so first we make a backup of the self signed certificates (just in case) by renaming these files as folows:

/etc/ssl/mail/mail.key to /etc/ssl/mail/mail.key.bak
/etc/ssl/mail/mail.crt to /etc/ssl/mail/mail.crt.bak

Then, once the files have been renamed we create symlinks from the Let’s Encrypt certificate. You’re probably wondering why we’re creating symlinks and not replacing the original files by doing a copy or move as recommended in the original notes, right? Well, we’re basically automating Let’s Encrypt renewal so if we do so we won’t have to copy or move the files each time the certificate is renewed.

Therefore, we setup the symlinks with the following commands:

ln -s /etc/letsencrypt/live/ /etc/ssl/mail/mail.key
ln -s /etc/letsencrypt/live/ /etc/ssl/mail/mail.crt

(Again, replace with your own)

Once the symlinks are in place you can restart the services that use the SSL certificates in order for them to work using the newly generated Let’s Encrypt certificates:

service postfix restart && service dovecot restart && service nginx restart

If no errors are returned it means that you did a very good job 😉 so far, because the work isn’t over just yet as we still have to automate the renewal of the SSL certificate so first and foremost we create a log file for certbot to write to:

touch /var/log/certbot-cron.log

Then we edit the crontab file using crontab -e and add the following cronjob:

* * 1 * * certbot renew –text >> /var/log/certbot-cron.log && service nginx reload

This will run the certbot renewal on the 1st day of each month and if the certificate expiration date is lower than 30 days it will be automatically renewed.

One last thing. You can check the SSL certificate here and the proper functionality of Postfix here.

When checking Postfix functionality you may receive the following warning:

Note: Cert failures do not affect TLS encryption, but may mean the site isn’t who they say they are.

This happens whenever your email’s MX records are different from the server hostname. This is not a major security concern and can be fixed by setting the MX records to the mail server’s hostname.