Introduction

Let's Encrypt validates domain ownership through ACME challenges before issuing certificates. The HTTP-01 challenge requires serving a specific token over HTTP, while DNS-01 requires creating a TXT record. Challenge failures prevent certificate issuance and often stem from network configuration, DNS issues, or server setup problems.

Symptoms

  • Certbot fails with: Failed to authorize domain
  • Error: Challenge failed for domain example.com
  • HTTP-01: The client lacks sufficient authorization
  • DNS-01: DNS problem: DNS record not found
  • Multiple retry attempts all failing
  • Challenge validation timeout errors
  • Certificates stuck in pending state

Common Causes

  • HTTP-01: Challenge path not accessible via HTTP
  • HTTP-01: Server redirects challenge URL incorrectly
  • HTTP-01: Firewall blocking port 80
  • HTTP-01: Web server not serving challenge directory
  • DNS-01: TXT record not created or propagated
  • DNS-01: Wrong DNS zone updated
  • DNS-01: API credentials for DNS provider incorrect
  • DNS-01: DNS propagation delay too short

Step-by-Step Fix

Step 1: Identify Challenge Type and Error

```bash # Check certbot logs for specific error certbot certificates 2>&1 | tail -50

# Run with verbose output certbot certonly -v -d example.com

# Check challenge status certbot certificates | grep -A 5 "example.com" ```

Step 2: Fix HTTP-01 Challenge Failures

```bash # Test if challenge URL is reachable # Certbot creates token in webroot, CA tries to fetch it

# Check if port 80 is accessible curl -I http://example.com/.well-known/acme-challenge/test-token

# Test from external network (not localhost) curl -I http://example.com:80/

# Check firewall rules iptables -L -n | grep 80 ufw status | grep 80 ```

Common HTTP-01 fixes:

```bash # Ensure webroot is correct certbot certonly --webroot -w /var/www/html -d example.com

# Or use standalone mode (stop web server temporarily) systemctl stop nginx certbot certonly --standalone -d example.com systemctl start nginx

# Or use nginx/apache plugin certbot --nginx -d example.com certbot --apache -d example.com ```

Fix redirect issues:

```nginx # Make sure challenge path isn't redirected # Nginx config exception location /.well-known/acme-challenge/ { root /var/www/html; # Don't redirect this path }

# Before your HTTPS redirect: location / { return 301 https://$host$request_uri; } ```

bash
# Verify challenge path works
mkdir -p /var/www/html/.well-known/acme-challenge/
echo "test-content" > /var/www/html/.well-known/acme-challenge/test-token
curl http://example.com/.well-known/acme-challenge/test-token
# Should return "test-content"

Step 3: Fix DNS-01 Challenge Failures

```bash # Check if TXT record exists dig _acme-challenge.example.com TXT

# Check from authoritative server dig @ns1.example.com _acme-challenge.example.com TXT

# Check DNS propagation # Use online tools like: # https://dnschecker.org/#TXT/_acme-challenge.example.com ```

Manual DNS-01 fix:

```bash # Get TXT record value from certbot certbot certonly --manual --preferred-challenges dns -d example.com

# Certbot will show output like: # "Please deploy a DNS TXT record under the name: # _acme-challenge.example.com with the value: # abc123xyz..."

# Create TXT record in your DNS control panel # Wait for propagation (5-10 minutes typically) dig _acme-challenge.example.com TXT

# Press Enter in certbot to continue validation ```

Automated DNS-01 with Cloudflare:

```bash # Install Cloudflare plugin pip install certbot-dns-cloudflare

# Create credentials file cat > /root/.cloudflare.ini << EOF dns_cloudflare_api_token = your_api_token_here EOF chmod 600 /root/.cloudflare.ini

# Request certificate certbot certonly --dns-cloudflare \ --dns-cloudflare-credentials /root/.cloudflare.ini \ -d "*.example.com" -d "example.com" ```

With acme.sh for other providers:

```bash # Install acme.sh curl https://get.acme.sh | sh

# Cloudflare export CF_Token="your_api_token" acme.sh --issue -d "*.example.com" -d "example.com" --dns dns_cf

# Route53 export AWS_ACCESS_KEY_ID="xxx" export AWS_SECRET_ACCESS_KEY="xxx" acme.sh --issue -d "*.example.com" --dns dns_aws

# DigitalOcean export DO_API_TOKEN="xxx" acme.sh --issue -d "*.example.com" --dns dns_dgon

# GoDaddy export GD_Key="xxx" export GD_Secret="xxx" acme.sh --issue -d "*.example.com" --dns dns_gd ```

Step 4: Check Validation Timing

```bash # DNS propagation can take time # Wait before retrying

# For HTTP-01, ensure server is responding systemctl status nginx apache2

# For both, ensure no rate limiting from previous failures # 5 failures per hostname per hour limit ```

Step 5: Test with Staging Environment

```bash # Use staging to test without rate limits certbot certonly --staging --webroot -w /var/www/html -d example.com

# Or with acme.sh acme.sh --issue -d example.com --server letsencrypt_test

# Once working, switch to production certbot certonly --webroot -w /var/www/html -d example.com ```

Step 6: Verify Certificate Issuance

```bash # After successful challenge certbot certificates

# Check certificate details openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text

# Test HTTPS curl -vI https://example.com openssl s_client -connect example.com:443 -servername example.com ```

Common Pitfalls

  • Redirecting HTTP to HTTPS before challenge path exception
  • Firewall blocking port 80 while trying HTTP-01
  • DNS propagation delay with DNS-01 challenges
  • Using wrong DNS zone (subdomain vs root domain)
  • Testing from localhost while external access differs
  • Not waiting between failed validation retries
  • Rate limit exhaustion from repeated failures

Best Practices

  • Use staging environment (--staging) for testing
  • Add redirect exceptions for /.well-known/acme-challenge/
  • Use DNS-01 for wildcard certificates and internal domains
  • Automate DNS challenges with API plugins
  • Test challenge accessibility from external network
  • Monitor DNS propagation before proceeding
  • Keep port 80 accessible even if HTTPS-only site
  • Let's Encrypt Rate Limit Exceeded
  • ACME HTTP-01 Challenge Failing Due to Redirect
  • SSL Certificate Chain Incomplete
  • SSL Auto-Renewal Not Working