Skip to content
ssldays

Guide

Reload Apache after certificate renewal

Certbot renewed on disk but Apache still serves the old cert—graceful reload and deploy hooks after every ACME success.

Updated Apr 2, 2026 823 words

Apache keeps serving the old certificate until graceful reload loads new SSLCertificateFile paths—renewal on disk is not enough.

When this happens

certbot certificates shows a future notAfter but browsers still see yesterday's serial on the public site. Blue/green Apache behind a load balancer keeps serving an old cert on the passive color after certbot updated only active color PEM paths. Graceful reload skipped during black Friday freezes certbot success stories until checkout SSL still shows yesterday's serial.

Mod_md or certbot apache plugin worked once, then someone switched to certonly without deploy hooks. Hot spare passive nodes in Pacemaker may miss hooks tied only to active resource scripts.

First response

Certbot renewed on disk but Apache still serves the old cert—graceful reload and deploy hooks after every ACME success.

Searches for reload apache after ssl renewal usually mean automated renewal failed, succeeded locally but never reached the TLS listener, or hit Let's Encrypt rate limits. The fix is almost always permissions, challenge reachability, or a missing reload—not buying a longer-lived commercial cert as the first move.

For Reload Apache after certificate renewal, read the ACME or panel error verbatim, run a dry-run renewal if your stack supports it, then confirm what certificate strangers receive on port 443 after you deploy. Certificate files on disk lie; only live handshakes matter for users.

Apache will happily serve an expired fullchain from memory long after certbot dropped new PEMs on disk. Incidents labeled apache ssl renewal often mean httpd never received graceful. After every ACME success, confirm the running mod_ssl children load the updated SSLCertificateFile by checking serial via openssl, not file mtimes alone. Triage should capture timestamps, account URLs, and the last Boulder error type before infrastructure changes widen blast radius.

See also ACME DNS-01 challenge propagation delays and ACME HTTP-01 challenge failed 403.

Why renewal failed

Worker processes mmap certificate material at reload time. Touching symlinks under /etc/letsencrypt/live alone does not update TLS state. Central Certificate Store layouts require updating the store binding, not only copying PEMs into /etc/ssl—httpd may still reference an old thumbprint in the store metadata. Reload orchestration must know every httpd instance that binds customer IPs, including container sidecars.

Per-vhost paths sometimes point at copied PEMs instead of live symlinks, so certbot updates files Apache is not reading. FIPS modules occasionally forbid reloading without full restart; document that exception so on-call does not assume graceful always suffices on hardened images. Change windows should budget time for configtest on large vhost fleets before graceful signals.

Failed apachectl configtest blocks hooks quietly, leaving httpd on an expiring chain while cron reports success. Include apachectl -M output in change records when mod_ssl upgrades ship with distro updates.

On RHEL and Debian layouts, certbot commonly writes to /etc/letsencrypt/live while vhosts reference symlinks under /etc/ssl or per-site paths. Without a deploy hook running apachectl graceful, worker processes retain the old certificate until restart. mod_md and certbot apache plugins automate reload, but mixed manual edits bypass them. Clarify in tickets whether failure is validation, issuance, deploy, or listener presentment—teams too often mix these phases when reading logs.

Missing Apache reload is not solved by re-issuing a longer commercial cert if listeners still cache the old material. It is not identical to certbot failure when logs show success. It is not fixed by service apache2 restart on every renew if you never tested graceful impact on long-lived connections. Incident reviews should ask whether httpd reload ran on every instance that answered health checks, because autoscaling launches fresh nodes that never saw certbot hooks on the original member.

Common causes

These patterns drive most reload apache after ssl renewal tickets. They explain why automation logs look green while browsers or APIs still break.

Certbot certonly updated live symlinks but sites-enabled still reference archived paths from an old migration. deploy hook was chmod 700 without shebang and silently failed under cron.

Multiple apache instances on different ports share certificates but only one unit file received the reload hook. Docker sidecar terminated TLS while host apache still presented an old mount.

Graceful reload blocked because apachectl configtest failed on an unrelated vhost typo. SELinux denied reading new keys until restorecon was run manually. Multi-tenant cPanel-style hosts run distinct httpd instances; hooks attached only to the system default daemon miss customer vhosts.

Diagnose

Compare on-disk serial with the certificate served on port 443 after SNI. Record apachectl graceful timestamp next to certbot log timestamp; skew between them highlights missing or failing hooks immediately.

openssl x509 -noout -serial -in /etc/letsencrypt/live/HOST/cert.pem
echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | openssl x509 -noout -serial

Check certbot certificates notAfter against openssl from outside. Inspect /var/log/letsencrypt/letsencrypt.log for deploy hook stderr. Run apache2ctl -S to map which vhost owns the customer hostname before reloading the correct instance. When using OCSP stapling, restart stapling cache or reload twice if mod_ssl caches staple fetch errors tied to old issuer chains.

Fix step-by-step

Follow this sequence for reload apache after certificate renewal. Capture command output after each step so the next responder can pick up without rerunning destructive changes.

  1. Run apachectl -t and fix unrelated syntax errors blocking reload.
  2. Point vhosts at live symlinks or copy hooks must mirror paths.
  3. Add certbot deploy-hook calling apachectl graceful.
  4. Renew once with hooks enabled.
  5. Recompare serial externally.
  6. Check SELinux contexts if httpd cannot read new keys.
  7. Reload secondary instances on other ports if they share certs.
  8. Monitor live serial nightly.
  9. Archive redacted ACME logs and openssl transcripts in the ticket before closing.
  10. Schedule a follow-up dry-run before the next natural renewal window.

Verify the live certificate

OpenSSL

echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | openssl x509 -noout -dates -subject -issuer

Replace HOST with the public hostname on the certificate.

How to read the output

Compare openssl x509 -noout -serial -in /etc/letsencrypt/live/HOST/cert.pem with the certificate returned by openssl s_client to the public IP. A mismatch after renew proves apache has not reloaded or the wrong vhost answers SNI.

curl

curl -vI --connect-timeout 10 https://HOST/ 2>&1 | grep -Ei 'expire|SSL certificate|subject:|issuer:'

Replace HOST with the public hostname users request.

Roll out and verify

Standardize vhost SSLCertificateFile and SSLCertificateKeyFile on live symlinks. Add certbot renew-hook or deploy-hook calling apachectl graceful when apache2ctl -t passes.

Run configtest, reload, and immediately probe external openssl for new serial. If using multiple MPM workers, confirm all child PIDs restarted after graceful. After graceful, run apachectl status or fullstatus on busy hosts to confirm worker count recycled as expected.

Automate post-renew reload in infrastructure code. Monitor live serial against disk serial nightly. Document which apache instance fronts customer traffic in multi-tier layouts. Close the change only after serial verification from two independent networks, not only from the bastion that already had the new PEM cached locally.

What to automate

Post-renew hook failures should page before notAfter—do not rely on annual manual apachectl. Compare apache-reported certificate serial via mod_status or local openssl against public checks after every hook.

ssldays validates the certificate strangers handshake, catching missing graceful reloads early. ssldays highlights drift when graceful reload silently skipped on secondary nodes.

Frequently asked questions

Does certbot apache plugin reload?

When you use that plugin for issuance it can reload; certonly plus webroot does not. Always attach apachectl -t output before claiming reload succeeded.

Multiple apache instances?

Each instance that terminates TLS needs the hook; inventory all apache2/httpd units. Always attach apachectl -t output before claiming reload succeeded.

mod_ssl default vhost?

Wrong SNI may show a renewed default cert while the customer hostname still serves old material—map vhosts with apachectl -S. Always attach apachectl -t output before claiming reload succeeded.

When is full restart required?

Rarely for simple PEM rotations—graceful reload suffices when configtest passes. FIPS modules, broken graceful in prefork under extreme load, or shared memory corruption may need restart. Document restart criteria so on-call does not restart unnecessarily during peak traffic.

Monitor this hostname on a schedule

Live certificate checks and renewal reminders — not guesswork from PEM files.