Skip to content

Rate Limiting Commands & Usage

TL;DR: Use certbot --dry-run for testing and --staging for development to avoid consuming production rate limits—monitor issuance via Certificate Transparency logs and never use --force-renewal unnecessarily to preserve your 5 certificates per exact set per 7 days quota.

Overview

Certificate automation commands directly impact rate limit consumption, making proper command usage critical for preventing service disruptions. This guide provides practical command patterns for testing, development, production operations, and monitoring that help teams stay within Let's Encrypt's rate constraints. Understanding which commands consume rate limits and which provide safe testing enables reliable certificate management.

Production teams must distinguish between operations that consume rate limits and those that don't. Dry-run commands test configurations without requesting actual certificates, while staging environment requests use separate rate limit buckets with higher thresholds. Monitoring commands help track issuance rates and identify approaching limits before they cause operational issues.

Enterprise deployments benefit from automated monitoring scripts, renewal optimization strategies, and emergency recovery procedures. Implementing proper command patterns prevents common scenarios like exhausting the exact set of identifiers limit during troubleshooting or consuming new orders quota during bulk certificate operations.

Core Rate Limiting Commands

Certificate Management with Certbot

The certbot command is susceptible to rate limiting issues when dealing with Let's Encrypt's certificate issuance limits.

Key Limits to Remember:

  • 50 certificates per registered domain per 7 days (refills at 1 per 202 minutes)
  • 5 certificates per exact set of identifiers per 7 days (refills at 1 per 34 hours)
  • 5 authorization failures per identifier per hour (refills at 1 per 12 minutes)
# Basic certificate request
certbot certonly --webroot -w /var/www/html -d example.com

# Check current certificates
certbot certificates

# Test configuration without requesting certificates (ALWAYS DO THIS FIRST)
certbot --dry-run certonly --webroot -w /var/www/html -d example.com

Common Issue Pattern:

When troubleshooting SSL configurations, repeatedly running certbot to fix issues can quickly consume your exact set of identifiers limit (5 per 7 days). This creates a cascading problem where each failed attempt with the same domain set consumes your quota.

Best Practice Implementation:

#!/bin/bash
# Always test first with dry-run
certbot --dry-run certonly --webroot -w /var/www/html -d example.com

# Only proceed if dry-run succeeds
if [ $? -eq 0 ]; then
    echo "Dry run successful, proceeding with actual certificate request"
    certbot certonly --webroot -w /var/www/html -d example.com
else
    echo "Dry run failed - fix issues before requesting actual certificate"
    exit 1
fi

Development and Testing Commands

Staging Environment Setup

Always use Let's Encrypt's staging environment for testing. The staging environment has significantly higher rate limits and is designed for development and troubleshooting.

# Use staging server for testing (RECOMMENDED for all development)
certbot certonly --staging \
    --webroot -w /var/www/html \
    -d test.example.com \
    --email [email protected]

# Test staging renewal
certbot renew --staging --dry-run

# Production deployment ONLY after staging validation
certbot certonly --webroot -w /var/www/html -d example.com --email [email protected]

Development Workflow Commands

# Step 1: Initial testing with staging + dry-run
certbot certonly --staging --dry-run \
    --webroot -w /var/www/html -d dev.example.com

# Step 2: Get staging certificate (doesn't affect production limits)
certbot certonly --staging \
    --webroot -w /var/www/html -d dev.example.com

# Step 3: Production certificate (only after staging success)
certbot certonly \
    --webroot -w /var/www/html -d example.com

Advanced Certificate Renewal Commands

Force Renewal Considerations

The --force-renewal flag forces certificate renewal regardless of expiry date. Use with extreme caution due to its impact on rate limits.

# Standard renewal (recommended - only renews if needed)
certbot renew

# Force renewal (USE WITH CAUTION)
certbot renew --force-renewal

# Force renewal for specific certificate (USE WITH CAUTION)
certbot renew --cert-name example.com --force-renewal

Critical Warning: Using --force-renewal unnecessarily:

  • Causes excessive load on Let's Encrypt systems
  • Consumes your Exact Set of Identifiers limit (5 per 7 days)
  • Reserve this flag for genuine emergencies only

Enterprise Implementation Pattern:

#!/bin/bash
# Enterprise-grade renewal script with rate limit protection

CERT_NAME="example.com"
DAYS_BEFORE_EXPIRY=30

# Check if renewal is actually needed
CERT_INFO=$(certbot certificates --cert-name "$CERT_NAME" 2>/dev/null)
EXPIRY_DATE=$(echo "$CERT_INFO" | grep "Expiry Date" | awk '{print $3, $4, $5, $6}')

if [ -z "$EXPIRY_DATE" ]; then
    echo "Certificate not found: $CERT_NAME"
    exit 1
fi

EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_TO_EXPIRY=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

echo "Certificate expires in $DAYS_TO_EXPIRY days"

if [ $DAYS_TO_EXPIRY -lt $DAYS_BEFORE_EXPIRY ]; then
    echo "Renewal needed, proceeding..."
    certbot renew --cert-name "$CERT_NAME"
else
    echo "Certificate still valid for $DAYS_TO_EXPIRY days - no renewal needed"
fi

Rate Limit Monitoring Commands

Status and Monitoring

# Check current certificate status
certbot certificates

# View detailed certificate information
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout

# Check certificate expiry date specifically
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -enddate -noout

# Monitor rate limit errors in logs
grep -i "rate limit" /var/log/letsencrypt/letsencrypt.log | tail -20

Check Issued Certificates via Certificate Transparency

#!/bin/bash
# Check how many certificates have been issued for your domain
# Uses Certificate Transparency logs via crt.sh

DOMAIN="example.com"

echo "Checking certificates issued for $DOMAIN in the last 7 days..."

# Query crt.sh (public Certificate Transparency log aggregator)
curl -s "https://crt.sh/?q=${DOMAIN}&output=json" | \
    jq '[.[] | select(.not_before > (now - 604800 | todate))] | length' 2>/dev/null

echo "Remember: Limit is 50 certificates per registered domain per 7 days"

Automated Monitoring Script

#!/bin/bash
# Rate limit monitoring for enterprise environments

DOMAIN="example.com"
LOG_FILE="/var/log/certbot-monitor.log"
ALERT_THRESHOLD=40  # Alert at 80% of 50 limit

check_rate_limits() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

    # Count certificates issued in last 7 days via crt.sh
    local count=$(curl -s "https://crt.sh/?q=${DOMAIN}&output=json" | \
        jq '[.[] | select(.not_before > (now - 604800 | todate))] | length' 2>/dev/null)

    if [ -z "$count" ] || [ "$count" = "null" ]; then
        echo "$timestamp: ERROR - Could not query crt.sh" >> $LOG_FILE
        return 1
    fi

    echo "$timestamp: Certificates issued this week for $DOMAIN: $count/50" >> $LOG_FILE

    if [ "$count" -ge "$ALERT_THRESHOLD" ]; then
        echo "$timestamp: WARNING - Approaching rate limit (${count}/50)" >> $LOG_FILE
        # Send alert to monitoring system
        curl -X POST "https://monitoring.example.com/alert" \
            -H "Content-Type: application/json" \
            -d "{\"severity\":\"warning\",\"message\":\"Rate limit warning for $DOMAIN: ${count}/50 certificates\"}" \
            2>/dev/null
    fi
}

check_rate_limits

Troubleshooting Commands

Rate Limit Recovery

When you've hit a rate limit, Let's Encrypt cannot manually reset it. Your capacity will gradually refill over time.

# Check if rate limited (use dry-run to test without consuming limits)
certbot certonly --dry-run --webroot -w /var/www/html -d example.com

# View recent certbot activity
journalctl -u certbot --since "1 week ago" | grep -i "rate\|limit\|error"

# Check certbot logs for rate limit messages
grep -E "(rate limit|too many)" /var/log/letsencrypt/letsencrypt.log

# Clean up duplicate certificates (if any)
certbot delete --cert-name example.com-0001

Workaround for Exact Set of Identifiers Limit

If you've hit the "5 certificates per exact set of identifiers" limit, you can request a certificate with a different set of identifiers:

# Original request (hit limit)
# certbot certonly -d example.com -d www.example.com

# Workaround: Add another identifier to create a different set
certbot certonly -d example.com -d www.example.com -d blog.example.com

# Note: This new certificate will be subject to:
# - New Orders per Account limit (300 per 3 hours)
# - New Certificates per Registered Domain limit (50 per 7 days)

Emergency Procedures

# If rate limited, optimize renewal configuration
# Renew earlier (default is 30 days before expiry)
echo "renew_before_expiry = 45 days" >> /etc/letsencrypt/renewal/example.com.conf

# Set up automated renewal check
echo "0 0,12 * * * root certbot renew --quiet" > /etc/cron.d/certbot-renew

# Monitor for when rate limit resets
# Rate limit error messages include retry time, e.g.:
# "retry after 2025-01-28 15:30:00 UTC"

Command Quick Reference

Task Command Notes
Test configuration certbot --dry-run certonly -d example.com Always do this first
Use staging certbot --staging certonly -d example.com For development/testing
Check certificates certbot certificates Shows expiry dates
Standard renewal certbot renew Only renews if needed
View logs journalctl -u certbot Check for errors
Check CT logs curl "https://crt.sh/?q=example.com" Count recent issuances

Important Reminders

  1. Always use --dry-run first before actual certificate requests
  2. Use staging environment for all development and troubleshooting
  3. Monitor your issuance rate via Certificate Transparency logs
  4. Avoid --force-renewal unless absolutely necessary
  5. Revoking certificates does NOT reset rate limits
  6. Rate limit errors include Retry-After - parse and respect this header