Let’s Encrypt with Exim and Dovecot

Following my post on setting up Let’s Encrypt with nginx, I experimented with installing the certificates from letsencrypt on my mail server. It was surprisingly straightforward. The key was that the verification of the domain, which requires port 80 or port 443 to be accessible on the host of the mail server. I run a secure mail server with Dovecot and Exim. Since on the server, nothing was hosted on port 80, I used the standalone plugin that runs a temporary standalone HTTP server for letsencrypt / certbot to access:

./certbot-auto certonly –standalone -d mail.example.com

After running the command, the certificates were downloaded to /etc/letsencrypt and what remained was only a matter of changing the configs of Exim and Dovecot:

Exim 4:

tls_certificate = /etc/letsencrypt/live/mail.example.com/fullchain.pem
tls_privatekey = /etc/letsencrypt/live/mail.example.com/privkey.pem


ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem

One caveat that I found was that Exim could not read the certificate and private key on the default letsencrypt permissions. While not ideal, I needed loosen the permissions:

sudo chmod 711 /etc/letsencrypt/live
sudo chmod 711 /etc/letsencrypt/live/mail.example.com
sudo chmod 711 /etc/letsencrypt/archive
sudo chmod 711 /etc/letsencrypt/archive/mail.example.com
sudo chmod 744 /etc/letsencrypt/archive/mail.example.com/*

Lastly, I setup a cron job which will renew the certificate on expiry. Despite being in beta, Let’s Encrypt is proving to be quite stable and useful!

10 thoughts on “Let’s Encrypt with Exim and Dovecot

  1. Jonathan

    Check what UID your exim instance is running as; add that user to a group ssl-cert or similar (unless it’s already in one) and change the group of the cert files to that user, rather than opening them up to anyone.

  2. Max

    I had to assign group ssl-cert to /etc/letscrypt/archive and /etc/letscrypt/live paths with appropriate read permission, then enroll user Debian-exim into this group.

  3. piem

    Changing the permissions of the files in `/etc/letsencrypt` is really not advisable.

    For dovecot, no change is needed since the certificates are accessed as root.

    For exim, the following would be enough to let exim access thos files:

    # adduser Debian-exim www-data

    A safer approach would be to create a group and have both exim and www-data be part of it, but i’m not sure whether certbot will override the permissons on these folders. Something like that:

    # addgroup sslcerts
    # adduser www-data sslcerts
    # adduser Debian-exim ssl-certs
    # chgrp ssl-certs /etc/letsencrypt/{archive,live}

  4. chris

    you may even want a job to copy them or bind mount them somewhere else as I can see selinux or app amour causing a few issues otherwise

  5. NoseyNick

    Any advice for an exim server that handles many many domains?

    I believe tls_certificate and tls_privatekey are expanded / expandable, but it’s not clear if / how much I can trust $tls_in_sni to contain a useful domain, or any domain, or any value at all, and I presumably have to beware of $tls_in_sni containing cheeky stuff like ‘../../../path/to/something/dubious’…

    … and then it’s perfectly legal to receive 1 connection for multiple emails, or even for one email to have multiple “RCPT To” in multiple domains, but I can’t use multiple tls_privatekeys, nor (presumably?) easily switch mid-connection.

    It’s also not clear how other servers behave – if a server connects to me, but then isn’t happy with my tls_certificate, will it assume a man-in-the-middle? Disconnect and retry “in the clear”? Tolerate any invalid cert ‘cos *SOME* encryption is better than no encryption at all?

    It’s not even 100% clear whether SNI is expected to contain the domain it’s trying to send to, or the MX server name, or possibly multiple values – can SNI send multiple values?


  6. Loune Post author

    @NoseyNick In regards to the TLS certificate subject host name, I think a lot of connecting SMTP servers don’t actually care or even validate certificates before accepting them. According to some discussion here (https://serverfault.com/questions/389413/what-host-name-should-the-ssl-certificate-for-an-smtp-server-contain) the rules for name validation is not very clearly defined in the RFCs. How I imagined it when I wrote this guide, and I think the most widely accepted way of doing it, is that it should correspond to the hostname value of the MX record of the domain. In this form, you don’t need to support multiple certificates for different email domains, as long as the MX record contains the same hostname. Most checker’s like https://www.sslshopper.com/ssl-checker.html#hostname=smtp.gmail.com:465 validate as such.

    Also check out the new MTA-STS (RFC8461) spec, if you want better email security: https://www.hardenize.com/blog/mta-sts

  7. NoseyNick

    OK, looks like I was here SIXTEEN MONTHS ago, so took me quite some time to work out how to get CertBot to request LetsEncrypt WILDCARD certs with ACME DNS auth, but now I have “noseynick.net, *.noseynick.net”, and repeated for a bunch of other vanity/club/friends/project domains, so should be good accepting mail to various addresses @noseynick.com at mail.noseynick.net as soon as I’ve worked out a secure enough way to set tls_certificate and tls_privatekey based on $tls_in_sni IF AND ONLY IF it’s a “safe” SNI, to a valid/existing /etc/letsencrypt/live/$safe_version_of_tls_in_sni/, probably with a default/fallback otherwise. Will let you know how it goes.

    Yup general advice seems to be, for example:

    yahoo.com mail is handled by 1 mta6.am0.yahoodns.net.
    yahoo.com mail is handled by 1 mta7.am0.yahoodns.net.
    yahoo.com mail is handled by 1 mta5.am0.yahoodns.net.
    … and those SMTP servers have certs for *.am0.yahoodns.net. NOT for yahoo.com

    google.com mail is handled by 50 alt4.aspmx.l.google.com.
    google.com mail is handled by 20 alt1.aspmx.l.google.com.
    google.com mail is handled by 40 alt3.aspmx.l.google.com.
    google.com mail is handled by 10 aspmx.l.google.com.
    google.com mail is handled by 30 alt2.aspmx.l.google.com.
    … and those servers have a cert with a WHOLE BUNCH of SANs including alt[1234].aspmx.l.google.com and aspmx.l.google.com but not google.com itself

    gmail.com similar story, it looks like the cert is supposed to be good for the MX HOSTNAME not the domain. Which kinda makes sense but was worth confirming. You’re certifying the mail SERVER not the DOMAIN(s).

    … and means for CertBot/LetsEncrypt you need to EITHER have a webserver on your mail.example.com (ick!), OR use the ACME DNS auth so you can add a TXT token to your DNS and get a wildcard cert good for *.example.com

  8. Leo Vdw.

    Use –post-hook:
    $ ./certbot-auto certonly –standalone -d mail.example.com –post-hook post.sh

    Which contains:
    cp /etc/letsencrypt/live/mail.example.com/fullchain.pem /etc/exim/
    cp /etc/letsencrypt/live/mail.example.com/privkey.pem /etc/exim/
    chown mailnull /etc/exim/privkey.pem

    fullchain.pem already was r r r – so was no issue

Leave a Reply

Your email address will not be published. Required fields are marked *