How to Gracefully Reload Apache HTTPD SSL Certificates After Certbot Renewal Without Restart


5 views

Many sysadmins using Let's Encrypt certificates with Apache HTTPD encounter this scenario: you've successfully renewed certificates using certbot renew --webroot, but Apache continues serving the old certificates. This happens because Apache caches SSL certificates in memory and doesn't automatically detect filesystem changes.

Instead of a full restart, Apache provides a graceful reload mechanism that:

  • Maintains existing connections
  • Applies configuration changes
  • Loads renewed certificates
# The proper way to reload certificates
sudo systemctl reload apache2  # For systemd systems
# OR
sudo service apache2 reload    # For SysVinit systems
# OR directly using apachectl
sudo apachectl graceful

For seamless renewals, add this to your Certbot renewal hook:

# /etc/letsencrypt/renewal-hooks/post/reload-apache.sh
#!/bin/bash
systemctl reload apache2 || apachectl graceful

Make it executable:

chmod +x /etc/letsencrypt/renewal-hooks/post/reload-apache.sh

After renewal and reload, verify with:

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com | openssl x509 -noout -dates

Compare with your certificate files:

openssl x509 -noout -dates -in /etc/letsencrypt/live/yourdomain.com/cert.pem

For special cases, you can configure Apache to check certificates more frequently:

# In your SSL VirtualHost configuration
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
SSLUseStapling on
# Refresh certificates every 6 hours (21600 seconds)
SSLStaplingStandardCacheTimeout 21600

Many sysadmins using Certbot with the --webroot plugin encounter this scenario:

# Certbot reports success
sudo certbot renew --webroot -w /var/www/html/

# But Apache keeps serving old certificate
openssl s_client -connect example.com:443 | openssl x509 -noout -dates

Apache doesn't automatically reload SSL certificates after renewal. The certificates are cached in memory until one of these occurs:

  • Full service restart (systemctl restart httpd)
  • Graceful reload (systemctl reload httpd)
  • Sending the HUP signal (kill -HUP $(pidof httpd))

Here's the proper way to handle certificate renewal without service interruption:

# 1. Renew certificates
sudo certbot renew --webroot -w /var/www/html/ --post-hook "systemctl reload apache2"

# Alternative method using hook scripts
sudo certbot renew --webroot -w /var/www/html/ --deploy-hook "/etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh"

Create /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh:

#!/bin/sh
# Check if renewal actually occurred
if [ -n "$RENEWED_DOMAINS" ]; then
    # Reload Apache gracefully
    systemctl reload apache2 || systemctl reload httpd
    logger "Reloaded Apache after Let's Encrypt renewal"
fi

After renewal and reload, verify with:

# Check certificate dates
openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

# Check Apache's loaded certificates
sudo apachectl -t -D DUMP_CERTS | grep -A10 "example.com"
  • Ensure the web server user (www-data/apache) has read access to /etc/letsencrypt/live/
  • Check SELinux contexts if using RHEL/CentOS: restorecon -Rv /etc/letsencrypt/
  • Verify symlinks in /etc/letsencrypt/live/ point to updated certificates

For cron-based renewal, use this in /etc/cron.d/certbot:

0 0,12 * * * root /usr/bin/certbot renew --quiet --post-hook "systemctl reload httpd"

Consider monitoring with:

  • Certificate expiration dates (Nagios/Icinga plugins)
  • Apache error logs for SSL-related issues
  • Certbot's renewal log at /var/log/letsencrypt/letsencrypt.log