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:
[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 directorySymptoms
- Apache fails to start or reload after certificate renewal
- Error log shows "No such file or directory" for the SSL certificate path
apachectl configtestreturns "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 thelive/symlink path
Step-by-Step Fix
- 1.Verify the actual certificate paths after renewal:
- 2.```bash
- 3.sudo certbot certificates
- 4.sudo ls -la /etc/letsencrypt/live/example.com/
- 5.
` - 6.The
live/directory contains symlinks to the current certificate inarchive/. - 7.Update Apache SSL configuration to use the correct symlink paths:
- 8.```apache
- 9.<VirtualHost *:443>
- 10.ServerName example.com
- 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.Verify file permissions on the certificate files:
- 2.```bash
- 3.sudo ls -la /etc/letsencrypt/live/example.com/
- 4.sudo ls -la /etc/letsencrypt/archive/example.com/
- 5.
` - 6.The Apache user (www-data) needs read access to the private key. The
archive/directory should have permissions0700owned byroot:root. - 7.Test the configuration before restarting:
- 8.```bash
- 9.sudo apachectl configtest
- 10.openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates
- 11.
` - 12.The first command verifies Apache can parse the config. The second confirms the certificate is valid and not expired.
- 13.Reload Apache to pick up the new certificate:
- 14.```bash
- 15.sudo systemctl reload apache2
- 16.sudo openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>&1 | openssl x509 -noout -dates
- 17.
`
Prevention
- Always use
live/symlink paths in Apache SSL configuration, never directarchive/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