Certbot renewal hooks cover the local actions that need to happen around certificate renewal. Configure a host-wide hook when the same action should apply to every certificate lineage on the server, such as stopping a listener before standalone validation or reloading a service after a renewed certificate is available.
Directory hooks live under Certbot's renewal-hooks tree and are separated by phase. The pre phase runs before a renewal attempt, the deploy phase runs after a successful issue or renewal, and the post phase runs after an attempted renewal finishes.
Use a deploy hook for service reloads because certbot renew can exit successfully when no certificate was close enough to expiry to renew. A dry-run renewal tests the ACME path, but deploy-hook behavior must be explicitly included in the verification command.
Related: Test Certbot certificate renewal
Related: Check the Certbot renewal timer
Related: Configure a Certbot deploy hook
Steps to configure a Certbot renewal hook:
- Choose the hook phase for the action.
Hook directory When it runs Use it for /etc/letsencrypt/renewal-hooks/pre Before a renewal attempt that will actually run Temporarily stopping a service that conflicts with validation, such as a standalone listener on port 80. /etc/letsencrypt/renewal-hooks/deploy After a successful issue or renewal Reloading a web server, syncing renewed certificate files, or notifying a dependent service. /etc/letsencrypt/renewal-hooks/post After a renewal attempt finishes Starting a service that was stopped by a matching pre hook, even if renewal failed. For a reload that should happen only when certificate files changed, use a deploy hook instead of checking the exit status from certbot renew.
- Create the deploy hook directory if it is missing.
$ sudo install -d -m 755 /etc/letsencrypt/renewal-hooks/deploy
- Create the hook script.
$ sudoedit /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh
#!/bin/sh set -eu printf 'Reloading nginx after renewal for %s\n' "${RENEWED_DOMAINS:-unknown}" systemctl reload nginxReplace systemctl reload nginx with the command that must run after a renewed certificate is available. Keep the script non-interactive because scheduled renewal may run from systemd or cron with no terminal.
Related: Reload Nginx after Certbot renewal - Make the hook executable.
$ sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh
- Confirm that Certbot can see the executable deploy hook.
$ sudo find /etc/letsencrypt/renewal-hooks/deploy -maxdepth 1 -type f -perm -111 -print /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh
Certbot runs executable directory hooks in byte-sorted filename order. Use prefixes such as 10-reload-nginx.sh and 20-sync-certs.sh when more than one hook must run in a specific sequence.
- Run the hook script once with sample renewal variables.
$ sudo env RENEWED_DOMAINS="www.example.com example.com" \ /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh Reloading nginx after renewal for www.example.com example.com
Fix script, permission, service, or reload errors before relying on unattended renewal. A hook error is printed by Certbot, but the hook failure is not the same signal as a failed certificate renewal.
- Run a renewal dry run and include deploy hooks in the test.
$ sudo certbot renew --dry-run --run-deploy-hooks Saving debug log to /var/log/letsencrypt/letsencrypt.log Processing /etc/letsencrypt/renewal/www.example.com.conf Simulating renewal of an existing certificate for www.example.com and example.com Reloading nginx after renewal for www.example.com example.com Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/www.example.com/fullchain.pem (success)
During --dry-run, pre and post hooks run by default when a renewal attempt happens. Deploy hooks run only when --run-deploy-hooks is included, and they use the currently active certificate files rather than the temporary staging certificate.
If the output says No simulated renewals were attempted., test on a host that already has a saved renewal configuration for the certificate lineage.
- Confirm that the normal renewal schedule will call the hook later.
$ systemctl list-timers --all '*certbot*' NEXT LEFT LAST PASSED UNIT ACTIVATES Fri 2026-06-12 12:33:10 UTC 4h 12min Fri 2026-06-12 00:18:42 UTC 8h ago certbot.timer certbot.service
The hook runs when the packaged renewal timer, cron job, or snap-managed schedule invokes certbot renew and a matching renewal phase occurs.
Related: Check the Certbot renewal timer
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.