Dovecot SSL Certificate Renewal

(May 12, 2021)

Just a quick technical note.

As mentioned before, I started self hosting email a while ago. Exactly three months ago, in fact, and I know this because that's how long Let's Encrypt SSL certificates are valid for. Yesterday, my email clients started complaining about an invalid certificate coming from my mail server.

After a few minutes of worrying if I'm being man-in-the-middled, I ssh'd into my VPS to debug.

TL;DR: Root cause and solution

Turns out when configuring Dovecot (the IMAP server I use), the SSL certificate you set is just a static string, not a filename pointing to a file that Dovecot will read every time it needs to serve it. As such, even after Certbot correctly got a new certificate, Dovecot was still using the old one.

This can be fixed by restarting Dovecot, allowing it to read the new certificate, assuming its available at the same path.

Long term solution

I already have a cronjob that runs certbot renew once a month to renew any SSL certificates going stale. I'm going to change it to instead point to a script that does

certbot renew
systemctl restart dovecot
to automate reloading the certificate.


A few things I learned while debugging this issue:

Viewing certificate info on the command line

My first step was to check the certificate I thought should have been served by Dovecot. In particular, I wanted to see its expiry date as well as compare its fingerprint to that reported by my mail client.

Certificates are stored in ASCII armor format, which is not human readable. Turns out you can get a human readable interpretation of your certificate with the openssl CLI tool:

openssl x509 -text -noout -in <certificate file>
will get you a detailed, human readable output. For example, you can find a "Validity" section, specifying the time period during which the certificate is valid.

Adding the -fingerprint flag will also output the fingerprint hash. The -noout flag is just there to suppress the output of the non-readable ASCII armor text.

Let's Encrypt certificate locations

Currently valid certificates from Let's Encrypt are stored under /etc/letsencrypt/live/<domain name>/. This is where my Dovecot server was configured to get its certificate from, so before I realized that the certificate is only read once, I was surprised that the fingerprint of the certificate stored here did not match the one my mail client was receiving.

Turns out Let's Encrypt also stores historic certificates under /etc/letsencrypt/archive/. Here I was able to find the certificate with a matching fingerprint to the faulty one received by my client, and confirm that it did indeed expire yesterday. Finding this is what led me to realizing how Dovecot handles its certificate configuration.

If you have any questions or comments about this post or site in general, feel free to email me.