Introduction

Let's Encrypt enforces rate limits to prevent abuse. When these limits are exceeded, certificate issuance fails and the existing certificate eventually expires, causing all HTTPS traffic to be blocked by browsers. The most commonly hit limit is the Duplicate Certificate limit (5 per week per exact set of domain names) and the Failed Validation limit (5 failures per account per hour). Understanding these limits and their workarounds is essential for maintaining site availability.

Symptoms

  • certbot renew fails with:
  • `
  • Error creating new order :: too many failed authorizations recently:
  • see https://letsencrypt.org/docs/failed-validation-limit/
  • `
  • Or:
  • `
  • Error creating new order :: too many certificates already issued for exact set of domains:
  • example.com: see https://letsencrypt.org/docs/rate-limits/
  • `
  • SSL certificate expires and browsers show:
  • `
  • Your connection is not private
  • NET::ERR_CERT_DATE_INVALID
  • `
  • ACME server returns:
  • `
  • 429 Too Many Requests
  • {
  • "type": "urn:ietf:params:acme:error:rateLimited",
  • "detail": "Error creating new order :: too many certificates (5) already issued..."
  • }
  • `

Common Causes

  • Certbot run too many times manually, hitting Duplicate Certificate limit
  • DNS validation failing repeatedly, hitting Failed Validation limit
  • Multiple servers/instances all trying to renew the same certificate
  • Wildcard certificate renewal failing due to DNS API issues
  • Staging environment using production Let's Encrypt endpoint for testing
  • Certificates not being renewed automatically due to cron/systemd timer failure

Step-by-Step Fix

  1. 1.Check current rate limit status:
  2. 2.```bash
  3. 3.# Check Let's Encrypt rate limits for your domain
  4. 4.curl -s https://letsencrypt.org/docs/rate-limits/

# Check your certificate issuance history crt.sh | example.com # Visit: https://crt.sh/?q=example.com

# Check certbot's local state certbot certificates ```

  1. 1.Understand the current rate limits:
  2. 2.- Duplicate Certificate: 5 per week per exact set of domain names
  3. 3.- Failed Validation: 5 per hour per account
  4. 4.- Certificates per Domain: 50 per week
  5. 5.- New Registrations: 10 per 3 hours per IP
  6. 6.- New Orders: 300 per 3 hours per account
  7. 7.Work around Duplicate Certificate limit by adding a subdomain:
  8. 8.```bash
  9. 9.# If you need a new cert for example.com but hit the limit,
  10. 10.# add a subdomain to change the "exact set of domains":
  11. 11.certbot certonly --nginx \
  12. 12.-d example.com -d www.example.com -d renew.example.com

# The set {example.com, www.example.com, renew.example.com} # is different from {example.com, www.example.com} # so it gets its own rate limit bucket ```

  1. 1.Fix Failed Validation issues:
  2. 2.```bash
  3. 3.# Check DNS resolution for the ACME challenge
  4. 4.dig _acme-challenge.example.com TXT

# For HTTP-01 validation, ensure the challenge file is accessible: curl -I http://example.com/.well-known/acme-challenge/test-file

# Common fix: ensure webroot is correct certbot certonly --webroot \ -w /var/www/example.com \ -d example.com -d www.example.com \ --dry-run # Test without consuming rate limit ```

  1. 1.Use the staging environment for testing:
  2. 2.```bash
  3. 3.# Always test with staging first (separate, more generous rate limits)
  4. 4.certbot certonly --nginx \
  5. 5.-d example.com -d www.example.com \
  6. 6.--staging \
  7. 7.--dry-run
  8. 8.`
  9. 9.Fix the automatic renewal timer:
  10. 10.```bash
  11. 11.# Check if the systemd timer is active
  12. 12.systemctl status certbot.timer

# If not active, enable it systemctl enable --now certbot.timer

# Or use cron crontab -l | grep certbot # Should have: # 0 */12 * * * certbot renew --quiet --no-self-upgrade

# Test renewal in dry-run mode certbot renew --dry-run ```

  1. 1.Switch to a different CA temporarily (emergency only):
  2. 2.```bash
  3. 3.# If Let's Encrypt rate limits are blocking you and cert is about to expire,
  4. 4.# you can use ZeroSSL or Google Trust Services as a temporary measure

# With acme.sh: acme.sh --issue -d example.com -d www.example.com \ --server zerossl \ --webroot /var/www/example.com

# With certbot (requires plugin): # See: https://certbot.eff.org/instructions for alternative CAs ```

Prevention

  • Run certbot renew --dry-run weekly to detect renewal issues early
  • Use a monitoring service that checks certificate expiry dates
  • Set alerts at 30, 14, and 7 days before certificate expiration
  • Never run certbot manually more than twice per week for the same domains
  • Always use --staging when testing new configurations
  • Use wildcard certificates to reduce the number of individual certificates needed
  • Store rate limit information in your runbook for on-call engineers