Renewing a Let's Encrypt Security certificate for Dovecot

Learning that lasts. Online courses from $14.99
A message appeared on a user's PC indicating the security certificate had expired for moonpoint.com today. The message came from Microsoft Outlook on her system. But when I checked the status of the system's security certificate in a browser by visiting moonpoint.com in the browser, it was still showing as valid until Friday, May 17, 2024 at 12:02:51 AM. I thought the email server software, Dovecot, running on the server was using the same security certificate as the Apache webserver. When I viewed the SSLCertificateFile and SSLCertificateChainFile lines in the Apache configuration file, /etc/httpd/conf/httpd.conf, I saw they were pointing to the following .pem files (.pem stands for "Privacy-Enhanced Mail" and a .pem file holds a security certificate).

SSLCertificateFile /etc/letsencrypt/live/support.moonpoint.com-0001/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/support.moonpoint.com-0001/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/support.moonpoint.com-0001/chain.pem

When I checked the expiration of that security certificate, I saw it was valid until May 17.

# openssl x509 -enddate -noout -in /etc/letsencrypt/live/support.moonpoint.com-0001/cert.pem
notAfter=May 17 04:02:51 2024 GMT
#

You can determine the location of the .pem file used by Dovecot by looking for the ssl_cert variable in /etc/dovecot/conf.d/10-ssl.conf.

# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = </etc/letsencrypt/live/support.moonpoint.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/support.moonpoint.com/privkey.pem

Since the .pem file specified by ssl_cert was a different .pem file than that being used by Apache, I checked the expiration date of the certificate in the specified .pem file and found it had expired earlier today.

#  openssl x509 -enddate -noout -in /etc/letsencrypt/live/support.moonpoint.com/fullchain.pem
notAfter=Mar 12 18:06:52 2024 GMT
#

When I tried renewing the certificate with a letsencryt renew command, it failed.

# letsencrypt renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/moonpoint.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Renewing an existing certificate for moonpoint.com and 2 more domains
Performing the following challenges:
http-01 challenge for moonpoint.com
http-01 challenge for www.moonpoint.com
Cleaning up challenges
Failed to renew certificate moonpoint.com with error: Problem binding to port 80: Could not bind to IPv4 or IPv6.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/support.moonpoint.com-0001.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/support.moonpoint.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Renewing an existing certificate for moonpoint.com and 5 more domains
Performing the following challenges:
http-01 challenge for moonpoint.com
http-01 challenge for www.moonpoint.com
http-01 challenge for imap.moonpoint.com
http-01 challenge for pop3.moonpoint.com
http-01 challenge for smtp.moonpoint.com
Cleaning up challenges
Failed to renew certificate support.moonpoint.com with error: Problem binding to port 80: Could not bind to IPv4 or IPv6.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
  /etc/letsencrypt/live/support.moonpoint.com-0001/fullchain.pem expires on 2024-05-17 (skipped)
All renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/moonpoint.com/fullchain.pem (failure)
  /etc/letsencrypt/live/support.moonpoint.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2 renew failure(s), 0 parse failure(s)

At first I thought I might need to stop the Apache webserver first, since I had encountered a similar problem in the past when renewing the webserver's security certificate as noted in Let's Encrypt Problem binding to port 80: Could not bind to IPv4 or IPv6, but when I stopped the webserver with apachectl stop and then issued the letsencrypt renew command, the renewal still failed, though the command did restart the Apache webserver. When I read Unable to renew LetsEncrypt certificate (HTTP-01 challenge failed), I thought the issue could be because I am redirecting connectivity to support.moonpoint.com to support.moonpoint.com/blog/blosxom, but I'm not using a HTTP 301 redirect as the person having the problem noted on that webpage was doing, instead I'm using a "refresh," i.e., <META HTTP-EQUIV="Refresh" CONTENT="0; URL=/blog/blosxom"> in the head section of the HTML code. I was finally able to resolve the problem when I looked at the options available for the letsencrypt renew with letsencrypt --help and saw there was a --apache parameter I could use.

# letsencrypt --help

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:

obtain, install, and renew certificates:
    (default) run   Obtain & install a certificate in your current webserver
    certonly        Obtain or renew a certificate, but do not install it
    renew           Renew all previously obtained certificates that are near
expiry
    enhance         Add security enhancements to your existing configuration
   -d DOMAINS       Comma-separated list of domains to obtain a certificate for

  --apache          Use the Apache plugin for authentication & installation
  --standalone      Run a standalone webserver for authentication
  (the certbot nginx plugin is not installed)
  --webroot         Place files in a server's webroot folder for authentication
  --manual          Obtain certificates interactively, or using shell script
hooks

   -n               Run non-interactively
  --test-cert       Obtain a test certificate from a staging server
  --dry-run         Test "renew" or "certonly" without saving any certificates
to disk

manage certificates:
    certificates    Display information about certificates you have from Certbot
    revoke          Revoke a certificate (supply --cert-name or --cert-path)
    delete          Delete a certificate (supply --cert-name)

manage your account:
    register        Create an ACME account
    unregister      Deactivate an ACME account
    update_account  Update an ACME account
  --agree-tos       Agree to the ACME server's Subscriber Agreement
   -m EMAIL         Email address for important account notifications

More detailed help:

  -h, --help [TOPIC]    print this message, or detailed help on a topic;
                        the available TOPICS are:

   all, automation, commands, paths, security, testing, or any of the
   subcommands or plugins (certonly, renew, install, register, nginx,
   apache, standalone, webroot, etc.)
  -h all                print a detailed help page including all topics
  --version             print the version number
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#

Using that parameter I was able to successfully renew the certificates with letsencrypt renew --apache. When I checked the expiration date for the certificate afterwards, I could see it was now valid until June 11, 2024.

#  openssl x509 -enddate -noout -in /etc/letsencrypt/live/support.moonpoint.com/fullchain.pem
notAfter=Jun 11 00:28:36 2024 GMT
#

I saw that there was a cron job that runs daily to check for the expiration of the security certificates on the system:

@daily /bin/certbot renew

When I checked the certbot and letsencrypt commands, I found that letsencrypt pointed to certbot, which in turn points to certbot-2 in the /usr/bin directory. So I edited the crontab entry that checks daily on whether certificates need to be renewed by running crontab -e from the root account and modified the certbot entry to be @daily /bin/certbot renew --apache (you need to use vi editor commands when you update the file with crontab -e).

# which certbot
/bin/certbot
# which letsencrypt
/bin/letsencrypt
# ls -l /bin/certbot
lrwxrwxrwx. 1 root root 18 Dec 24  2021 /bin/certbot -> /usr/bin/certbot-2
# ls -l /bin/letsencrypt
lrwxrwxrwx. 1 root root 16 Dec 24  2021 /bin/letsencrypt -> /usr/bin/certbot
# crontab -e

Now, checking the line with crontab -l, I have the following:

# crontab -l | grep certbot
@daily /bin/certbot renew --apache
#

References:

  1. Dovecot SSL configuration
    Dovecot manual
  2. Simple Guide: Using Lets Encrypt SSL certs with Dovecot
    By: prebelgian
    Date: November 2015
    Let's Encrypt Community Support
  3. Unable to renew LetsEncrypt certificate (HTTP-01 challenge failed)
    By: ell-site
    Date: March 12, 2024
    Let's Encrypt Community Support

Related:

  1. Let's Encrypt Problem binding to port 80: Could not bind to IPv4 or IPv6
    Date: April 5, 2022