How to reload Apache after Certbot renewal

Renewed Certbot files under /etc/letsencrypt/live/ do not automatically change the certificate already opened by a long-running Apache process. Add a deploy hook so Apache reloads after a successful renewal and starts serving the renewed certificate without waiting for the next manual service change.

Certbot deploy hooks run after a certificate is renewed successfully, which makes them a better fit than a post hook when the only job is to reload the web server after certificate material changes. Directory hooks under /etc/letsencrypt/renewal-hooks/deploy/ are also picked up by normal automated renewals, so the reload stays attached to the renewal process instead of living in a separate cron entry.

The commands below use the Debian and Ubuntu Apache layout with apache2ctl and the apache2 service name. Test the Apache configuration inside the hook before reloading; a renewed certificate path is not useful if a separate virtual host error would make the reload fail.

Steps to reload Apache after Certbot renewal:

  1. Confirm that the Apache service is running before wiring the renewal hook.
    $ sudo systemctl is-active apache2
    active

    If Apache is not active, fix the service state first. A renewal hook should reload the running web server after certificate changes, not hide an already-stopped service.

  2. Test the current Apache configuration.
    $ sudo apache2ctl configtest
    Syntax OK

    A fresh Debian or Ubuntu host may print the AH00558 fully qualified domain name warning before Syntax OK. The final Syntax OK line is the parser result; fix real syntax errors before adding the hook.

  3. Create the Certbot deploy-hook directory if it does not already exist.
    $ sudo install -d -m 755 /etc/letsencrypt/renewal-hooks/deploy

    Deploy hooks in this directory run after successful renewals. Use /etc/letsencrypt/renewal-hooks/post/ only for work that should happen after every renewal attempt, including failed attempts.

  4. Move into the deploy-hook directory.
    $ cd /etc/letsencrypt/renewal-hooks/deploy
  5. Create the Apache reload hook file.
    $ sudo vi reload-apache.sh
  6. Add a syntax test followed by a service reload.
    reload-apache.sh
    #!/bin/sh
    set -eu
     
    /usr/sbin/apache2ctl configtest
    /usr/sbin/apache2ctl graceful

    apache2ctl graceful asks Apache to re-read its configuration and continue serving with a new worker generation. On RHEL-family systems, use the matching apachectl or httpd control path for that host.

  7. Make the hook executable.
    $ sudo chmod 755 reload-apache.sh
  8. Run the hook manually before waiting for a real renewal.
    $ sudo ./reload-apache.sh
    Syntax OK

    apache2ctl graceful normally returns no output when it succeeds, so the visible success line is the Apache syntax test that ran before the graceful reload.

  9. Confirm that Apache stayed active after the manual hook test.
    $ sudo systemctl is-active apache2
    active

    If the service is not active after the hook runs, inspect the Apache journal before retrying renewal tests.

  10. Test the renewal path with deploy hooks enabled for the dry run.
    $ sudo certbot renew --dry-run --run-deploy-hooks
    Saving debug log to /var/log/letsencrypt/letsencrypt.log
    ##### snipped #####
    Congratulations, all simulated renewals succeeded:
      /etc/letsencrypt/live/www.example.com/fullchain.pem (success)

    Certbot dry runs do not run deploy hooks by default. The --run-deploy-hooks option makes the dry run execute deploy hooks so the Apache reload path is tested before the next real renewal.

  11. Confirm that the site is serving a renewed certificate after a real renewal.
    $ openssl s_client -servername www.example.com \
      -connect www.example.com:443 </dev/null 2>/dev/null | \
      openssl x509 -noout -subject -dates
    subject=CN=www.example.com
    notBefore=Jun 12 00:00:00 2026 GMT
    notAfter=Sep 10 23:59:59 2026 GMT

    Check the public hostname that users actually reach. Shared listeners, IPv6 records, reverse proxies, and load balancers can serve a different certificate than the local Apache process.