Introduction

After renewing an SSL certificate, Apache may refuse to start with an error indicating it cannot find the certificate file. This is common with Let's Encrypt certbot renewals where symlinks are updated but Apache configuration points to an old path, or when the certificate is renewed to a different location. The error appears as:

bash
[Mon Apr 08 21:00:00.123456 2026] [ssl:emerg] [pid 5678] AH02572: Failed to configure at least one certificate and key for example.com:443
[Mon Apr 08 21:00:00.123456 2026] [ssl:emerg] [pid 5678] SSL Library Error: error:02001002:system library:fopen:No such file or directory

Symptoms

  • Apache fails to start or reload after certificate renewal
  • Error log shows "No such file or directory" for the SSL certificate path
  • apachectl configtest returns "AH02572: Failed to configure at least one certificate and key"
  • The certificate exists at the renewal location but Apache configuration references the old path
  • Other virtual hosts with valid SSL configurations continue to work

Common Causes

  • Apache configuration points to a specific cert file instead of the live/ symlink
  • Certificate renewed to a new directory or with a different domain name
  • Permissions changed on the certificate directory after renewal
  • Certbot renewal updated the symlink but Apache had a cached reference to the old inode
  • Configuration uses absolute path to archive/ instead of the live/ symlink path

Step-by-Step Fix

  1. 1.Verify the actual certificate paths after renewal:
  2. 2.```bash
  3. 3.sudo certbot certificates
  4. 4.sudo ls -la /etc/letsencrypt/live/example.com/
  5. 5.`
  6. 6.The live/ directory contains symlinks to the current certificate in archive/.
  7. 7.Update Apache SSL configuration to use the correct symlink paths:
  8. 8.```apache
  9. 9.<VirtualHost *:443>
  10. 10.ServerName example.com
  11. 11.DocumentRoot /var/www/html

SSLEngine on SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem </VirtualHost> `` Always use the live/ symlink paths, never the archive/` paths.

  1. 1.Verify file permissions on the certificate files:
  2. 2.```bash
  3. 3.sudo ls -la /etc/letsencrypt/live/example.com/
  4. 4.sudo ls -la /etc/letsencrypt/archive/example.com/
  5. 5.`
  6. 6.The Apache user (www-data) needs read access to the private key. The archive/ directory should have permissions 0700 owned by root:root.
  7. 7.Test the configuration before restarting:
  8. 8.```bash
  9. 9.sudo apachectl configtest
  10. 10.openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates
  11. 11.`
  12. 12.The first command verifies Apache can parse the config. The second confirms the certificate is valid and not expired.
  13. 13.Reload Apache to pick up the new certificate:
  14. 14.```bash
  15. 15.sudo systemctl reload apache2
  16. 16.sudo openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>&1 | openssl x509 -noout -dates
  17. 17.`

Prevention

  • Always use live/ symlink paths in Apache SSL configuration, never direct archive/ paths
  • Add a post-renewal hook to automatically reload Apache after certbot renewals:
  • ```bash
  • sudo certbot renew --deploy-hook "systemctl reload apache2"
  • `
  • Or add a systemd timer that runs certbot renew --quiet --deploy-hook "systemctl reload apache2" twice daily
  • Monitor certificate expiration dates with a cron job:
  • ```bash
  • echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -checkend 2592000
  • `
  • This exits with code 1 if the certificate expires within 30 days.
  • Store SSL configuration in a version-controlled template so path changes are tracked