Let's Secure Me

Best practices and tips to secure your infrastructure.

ACME Automation & SSL Renewal Best Practices for 2026

Certbot, acme.sh, 6-day certificates, and ACME Renewal Information — keep your TLS certificates rotating without downtime.

An expired certificate is still the number-one cause of preventable HTTPS outages. The fix is straightforward — automate renewal — but "set up a cron job" understates what production-grade automation actually requires. You need to handle DNS and HTTP challenges reliably, monitor for silent failures, respect rate limits, and increasingly opt into shorter certificate lifetimes that demand tighter renewal cycles.

This guide covers the practical end-to-end workflow: choosing an ACME client, issuing your first certificate, wiring up renewal with proper reload hooks, adopting Let's Encrypt's new 6-day short-lived certificates, leveraging ACME Renewal Information (ARI) for smarter scheduling, and building a troubleshooting checklist for when things go wrong.

What Changed: Let's Encrypt in 2025-2026

Before diving into automation, it is worth understanding the recent changes that affect how you plan your renewal strategy:

  • 6-day short-lived certificates — available since February 2025, subscribers can opt into certificates valid for only six days. These should be renewed every three days (50% lifetime). Short-lived certificates reduce the window of exposure if a private key is compromised and eliminate the need for revocation checking (OCSP/CRL).
  • ACME Renewal Information (ARI) — Let's Encrypt now provides a renewal hint via the ARI extension (draft-ietf-acme-ari). Clients that support ARI receive a suggested renewal window from the CA, which helps spread renewal load and makes renewals exempt from rate limits.
  • Authorization caching for 30 days — once a domain validation succeeds, the authorization is cached for up to 30 days. Repeat certificate requests for the same domain skip revalidation within this window.
  • Updated rate limits — 300 new orders per account every 3 hours; 50 certificates per registered domain per week; 5 duplicate certificates per week. ARI-coordinated renewals are exempt from most limits.

Note: If you are running standard 90-day certificates and renewing at 60 days, your existing automation still works. But adopting 6-day certificates or ARI can meaningfully improve your security posture — and the migration path is straightforward.

Choosing an ACME Client

The two most widely deployed ACME clients are Certbot and acme.sh. Both are mature, well-maintained, and support the full ACME v2 protocol. Here is how they compare:

FeatureCertbotacme.sh
LanguagePythonPure shell (POSIX)
Root requiredTypically yesNo (runs as any user)
DNS providersVia plugins (~10)100+ built-in
Server integrationNginx/Apache pluginsManual install-cert
Renewal schedulersystemd timercron job
Default key typeRSA 2048ECDSA P-256

Recommendation: Use Certbot if you want the simplest path with Nginx/Apache auto-configuration. Use acme.sh if you need broad DNS API support, want to run unprivileged, or prefer zero external dependencies.

Step-by-Step: Certbot with Nginx

1. Install Certbot

# Ubuntu/Debian
sudo apt update && sudo apt install certbot python3-certbot-nginx -y

# Verify installation
certbot --version

2. Issue an ECDSA Certificate

# ECDSA P-256 — faster handshakes, smaller certificates
sudo certbot --nginx --key-type ecdsa --elliptic-curve secp256r1 \
  -d example.com -d www.example.com

Certbot's Nginx plugin automatically modifies your server block to add ssl_certificate and ssl_certificate_key directives and sets up the HTTP-to-HTTPS redirect.

3. Verify the Renewal Timer

# Check the systemd timer is active
systemctl status certbot.timer

# List scheduled timers
systemctl list-timers certbot.timer

The timer runs twice daily by default. Certbot only actually renews when a certificate is within 30 days of expiry.

4. Add a Deploy Hook

Critical: Certbot renews the certificate files on disk, but Nginx continues serving the old certificate from memory until reloaded. Without a deploy hook, your users see the old (eventually expired) certificate even though the new one exists on disk.

# Create a deploy hook that validates config before reloading
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/bash
nginx -t 2>/dev/null && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

5. Dry-Run Test

# Simulate renewal without touching real certificates
sudo certbot renew --dry-run

If the dry run succeeds, your automation is correctly wired. If it fails, check the troubleshooting section below.

Step-by-Step: acme.sh with DNS Validation

DNS-01 validation is the only challenge type that supports wildcard certificates and works behind firewalls where HTTP-01 cannot reach port 80. acme.sh has built-in support for 100+ DNS providers via API.

1. Install acme.sh

curl https://get.acme.sh | sh -s [email protected]

# Reload shell to pick up the alias
source ~/.bashrc

The installer creates ~/.acme.sh/, registers a daily cron job, and does not require root.

2. Export DNS API Credentials

# Example: Cloudflare API token
export CF_Token="your-cloudflare-api-token"
export CF_Zone_ID="your-zone-id"

Note: acme.sh saves these credentials in ~/.acme.sh/account.conf after the first use, so they persist across renewals. Use scoped API tokens with minimal permissions — for Cloudflare, a token with Zone:DNS:Edit on the specific zone is sufficient.

3. Issue a Wildcard Certificate

acme.sh --issue \
  -d example.com \
  -d '*.example.com' \
  --dns dns_cf \
  --keylength ec-256

4. Install the Certificate for Nginx

acme.sh --install-cert -d example.com \
  --key-file /etc/nginx/ssl/example.com.key \
  --fullchain-file /etc/nginx/ssl/example.com.fullchain.pem \
  --reloadcmd "nginx -t 2>/dev/null && systemctl reload nginx"

The --reloadcmd is saved and re-executed automatically on every renewal. Always include nginx -t before the reload to prevent a broken config from taking Nginx down.

5. Verify the Cron Job

# Check the cron entry exists
crontab -l | grep acme.sh

# Expected output (time may vary):
# 0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null

Adopting Let's Encrypt 6-Day Certificates

Short-lived certificates (valid for 6 days) reduce the risk window if a key is compromised and eliminate the dependency on OCSP for revocation. The tradeoff is that your renewal automation must be rock-solid — there is no 30-day buffer.

Renewal cadence

  • 90-day certificates: renew every 60 days (30-day buffer)
  • 6-day certificates: renew every 3 days (3-day buffer)

Requirements before switching

  • Your ACME client must support the short-lived certificate profile. Check your client's documentation for the flag or configuration option.
  • Renewal must run at least every 3 days — preferably multiple times daily for redundancy.
  • DNS-01 validation must propagate reliably within minutes if you use DNS challenges.
  • Monitoring and alerting must be in place to catch renewal failures within hours, not days.

Warning: Do not switch to 6-day certificates without first proving that your existing 90-day renewal automation is 100% reliable. Run --dry-run or --force renewal tests repeatedly and verify that the deploy hooks execute correctly every time. A single missed renewal means your site goes down within 3 days.

Recommended cron for 6-day certificates

# Run renewal checks every 8 hours (3x daily)
0 */8 * * * /usr/bin/certbot renew --quiet --deploy-hook "nginx -t && systemctl reload nginx"

ACME Renewal Information (ARI)

ARI is a protocol extension that allows the CA to suggest the optimal renewal window for each certificate. Instead of blindly renewing at a fixed offset (e.g., 30 days before expiry), the client asks the CA when to renew and receives a time window.

Benefits of ARI:

  • Rate limit exemption — ARI-coordinated renewals are exempt from most Let's Encrypt rate limits.
  • Incident-driven renewal — if Let's Encrypt needs to revoke certificates (e.g., due to a CA incident), ARI can push the renewal window forward, triggering early renewal before revocation.
  • Load distribution — ARI staggers renewals to prevent thundering-herd spikes on the CA infrastructure.

To benefit from ARI, ensure your ACME client is up to date. Certbot 2.7+ and recent versions of acme.sh include ARI support. The client handles it transparently — no manual configuration is required beyond keeping the client updated.

# Update Certbot to the latest version
sudo apt update && sudo apt install --only-upgrade certbot -y
certbot --version

# Update acme.sh
acme.sh --upgrade

Understanding Let's Encrypt Rate Limits

Hitting rate limits during an incident is a nightmare scenario — you cannot renew when you need it most. Here are the current limits and how to stay clear of them:

LimitValueRefill Rate
New orders per account300 / 3 hours1 per 36 seconds
Certificates per registered domain50 / 7 days1 per ~3.4 hours
Duplicate certificates (same name set)5 / 7 days1 per 34 hours
Failed validations per hostname5 / hour1 per 12 minutes

Best practices to avoid rate limit issues:

  • Use the staging environment (--staging or --test) for all testing and development. Staging has much higher limits.
  • Consolidate domains into fewer certificates using SANs instead of issuing one certificate per subdomain.
  • Fix validation errors (DNS propagation, firewall rules) before retrying — failed validations eat into your hourly limit.
  • Use ARI-enabled clients — ARI-coordinated renewals bypass most limits.

Monitoring and Alerting

Automated renewal is only as good as your monitoring. Silent failures — a DNS API key that expired, a firewall rule that changed, a full disk — will not announce themselves.

Certificate expiry check (cron)

#!/bin/bash
# check-cert-expiry.sh — alert if certificate expires within N days
DOMAIN="example.com"
WARN_DAYS=14

EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ "$DAYS_LEFT" -lt "$WARN_DAYS" ]; then
  echo "WARNING: $DOMAIN certificate expires in $DAYS_LEFT days ($EXPIRY)" | \
    mail -s "Certificate Expiry Warning: $DOMAIN" [email protected]
fi

What to monitor

  • Certificate expiry date — alert at 14 days (90-day certs) or 2 days (6-day certs).
  • Renewal log output — check /var/log/letsencrypt/letsencrypt.log (Certbot) or ~/.acme.sh/acme.sh.log for errors.
  • Deploy hook execution — verify Nginx actually reloaded by checking systemctl status nginx after renewal.
  • Certificate serial/fingerprint change — confirm the served certificate is actually the new one, not a stale cached copy.

Note: External monitoring services like UptimeRobot, Datadog, or a simple cron-based check from a separate server add an independent layer of verification. Do not rely solely on the same machine that runs renewal to also verify it succeeded.

Troubleshooting Checklist

When renewal fails, work through this checklist:

1. Is the ACME client up to date?

certbot --version        # should be 2.7+
acme.sh --version        # update with: acme.sh --upgrade

2. Can the server reach Let's Encrypt?

# Test outbound HTTPS connectivity
curl -sI https://acme-v02.api.letsencrypt.org/directory | head -1
# Expected: HTTP/2 200

3. Is port 80 reachable (HTTP-01 challenge)?

# From an external machine:
curl -sI http://example.com/.well-known/acme-challenge/test
# Should return 404 from your server, not a firewall block or CDN error

4. Is DNS propagation working (DNS-01 challenge)?

# Check if the TXT record is visible
dig -t TXT _acme-challenge.example.com +short
# Should return the challenge token value

5. Are you hitting rate limits?

# Check recent certificate issuance for your domain
# Visit: https://crt.sh/?q=example.com
# Count certificates issued in the last 7 days

6. Are DNS API credentials still valid?

# Test the API directly (Cloudflare example)
curl -s -H "Authorization: Bearer $CF_Token" \
  "https://api.cloudflare.com/client/v4/zones/$CF_Zone_ID" | jq '.success'

7. Is disk space available?

df -h /etc/letsencrypt
df -h ~/.acme.sh

8. Does the deploy hook work in isolation?

# Test the hook manually
nginx -t && systemctl reload nginx && echo "Hook OK"

FAQ

Can I use both Certbot and acme.sh on the same server?

Yes, but manage different domains with each to avoid conflicts. Both clients store state independently (/etc/letsencrypt/ vs ~/.acme.sh/) and will not interfere with each other as long as they are not issuing certificates for the same domain set.

Should I switch to 6-day certificates?

If your renewal automation is proven reliable and you have monitoring in place, 6-day certificates are strictly better from a security perspective. They reduce key compromise exposure from 90 days to 6, and eliminate the need for OCSP. Start by testing on a non-critical domain first.

What happens if renewal fails and the certificate expires?

Browsers will show a certificate error and most users will not proceed past it. Your site is effectively down. This is why monitoring and alerting are non-negotiable — you need to know about renewal failures within hours, not days.

Do I still need OCSP stapling with short-lived certificates?

With 6-day certificates, OCSP becomes less relevant because the certificate expires before most revocation workflows would complete. However, for 90-day certificates, OCSP stapling is still recommended to improve TLS handshake performance and privacy.

How do I test without hitting production rate limits?

Use the staging environment. Certbot: --staging. acme.sh: --test. Staging certificates are not trusted by browsers but the workflow is identical, and rate limits are much more generous.

My wildcard certificate renewal keeps failing. Why?

Wildcard certificates require DNS-01 validation, which means your DNS API credentials must remain valid and the API must be reachable. The most common causes are: expired API tokens, changed API permissions, DNS provider rate limiting, or slow DNS propagation. Check the DNS troubleshooting step above.

References

Conclusion

Certificate renewal automation is no longer optional — it is the baseline. With Let's Encrypt now offering 6-day certificates and ACME Renewal Information, the ecosystem is pushing toward shorter-lived credentials that are renewed frequently and automatically. The security benefits are real: a compromised key is useful for days instead of months.

The investment is modest: choose your ACME client, wire up a deploy hook that validates before reloading, add expiry monitoring from an independent vantage point, and test with --dry-run regularly. Get this foundation right and you will never page on an expired certificate again.