Skip to content

Certbot examples

These PowerShell 7 examples wrap Certbot and send the same CertIntel requests as scripts/simple-acme/:

  • /api/v1/checkins/start before every Certbot run
  • /api/v1/checkins after every run, even when nothing was due
  • /api/v1/renewals/enrich from the successful deploy hook, including the current and previous certificate thumbprints, validity, SANs, and lineage path
  • /api/v1/renewals for each successful issuance, plus a failure event when Certbot exits non-zero

Files

  • Request-Certificate.ps1 wraps certbot certonly.
  • Renew-Certificates.ps1 wraps certbot renew and is the script to schedule.
  • Deploy-Hook.ps1 consumes Certbot's RENEWED_LINEAGE and RENEWED_DOMAINS hook variables after each successful issuance.
  • CertIntel-Common.ps1 contains the shared API, PEM-reading, previous-certificate snapshot, and native-process wrapper functions.

The scripts require PowerShell 7 (pwsh) on the Certbot host. They are designed for Linux paths and work with Certbot's standard /etc/letsencrypt configuration directory. Run them as an account that can run Certbot and read that directory, normally root.

Create a unique CertIntel write key for this host (scoped to the target organization, with both renewals and checkins enabled), then make these environment variables available to the scheduled account. Authentication is a single header, X-Api-Key: cik_<prefix>.<secret>:

export CERTINTEL_API_URL='https://acme-corp.certintel.example/api/v1/renewals'
export CERTINTEL_CHECKINS_URL='https://acme-corp.certintel.example/api/v1/checkins'
export CERTINTEL_API_KEY='cik_XXXXXXXX.YYYYYYYYYYYYYYYYYYYYYYYY'   # full write-scoped token

Use a protected environment file or your service manager's credential facility for the secret. Do not put it directly in a systemd ExecStart command or cron line.

Request a certificate

Webroot example:

sudo -E pwsh -NoLogo -NoProfile -File ./Request-Certificate.ps1 \
  -Domain example.com,www.example.com \
  -Email admin@example.com \
  -WebRoot /var/www/html

Standalone example (port 80 must be available):

sudo -E pwsh -NoLogo -NoProfile -File ./Request-Certificate.ps1 \
  -Domain example.com \
  -Email admin@example.com \
  -Authenticator standalone

For DNS plugins, set -Authenticator to the installed plugin name and pass its remaining Certbot options as an array with -AdditionalArguments. Keep credential files readable only by the scheduled account. Use -Staging while proving challenge configuration.

The wrapper supplies Deploy-Hook.ps1 through --deploy-hook; do not separately install the same file in /etc/letsencrypt/renewal-hooks/deploy, or the issuance may be reported twice.

Renew certificates

Check every configured lineage:

sudo -E pwsh -NoLogo -NoProfile -File ./Renew-Certificates.ps1

Check one lineage or test renewal configuration against staging:

sudo -E pwsh -NoLogo -NoProfile -File ./Renew-Certificates.ps1 -CertName example.com
sudo -E pwsh -NoLogo -NoProfile -File ./Renew-Certificates.ps1 -DryRun

Schedule this wrapper instead of calling certbot renew directly, and replace or disable any preinstalled Certbot timer that still invokes the bare command. Certbot returns zero when nothing is due, so the wrapper always posts a completion check-in while the deploy hook is the authoritative signal that a certificate was actually issued. Dry runs post a check-in but intentionally suppress renewal/enrich payloads so staging certificates do not appear in production renewal history.

Before Certbot runs, the wrapper snapshots each current live/*/cert.pem thumbprint to a temporary file. The deploy hook uses that snapshot for OldCertThumbprint, preserving CertIntel's renewal-event replacement chain after Certbot updates the live links. The temporary file is deleted when the run ends and contains no private keys.

-ForceRenewal is for controlled testing only; routine use can exhaust CA rate limits.

Official references: