Fix Let's Encrypt Certbot ACME Verification Failed

Solve Certbot verification failures, DNS record issues, and HTTP-01 challenge timeouts during SSL certificate setup.


When generating or renewing an SSL certificate using Certbot, the Let’s Encrypt validation server verifies that you own the domain by requesting a specific challenge file over HTTP (the HTTP-01 challenge) or validating a DNS TXT record (the DNS-01 challenge).

A verification failure means Let’s Encrypt could not successfully reach your server or complete the challenge.


Symptom & Error Signature

Your Certbot logs or terminal output shows:

Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems:
  Domain: butitworkedlocal.com
  Type:   connection
  Detail: 192.0.2.1: Fetching http://butitworkedlocal.com/.well-known/acme-challenge/LHNf_3xsz...: Connection refused / Timeout

Root Cause Analysis

For HTTP-01 challenges, Let’s Encrypt sends an HTTP request to http://<your-domain>/.well-known/acme-challenge/<token>. This check fails if:

  1. DNS Mismatch: Your domain’s A or AAAA records point to the wrong server IP (or Cloudflare proxy is blocking it).
  2. Firewall Blocking: Port 80 (HTTP) is blocked by a firewall (like ufw, AWS Security Groups, or ChicagoVPS firewall panel).
  3. Nginx/Apache Routing Issues: The web server configuration is redirecting all HTTP traffic to HTTPS before the challenge folder can be read, or it is blocking access to hidden directories starting with a dot (.well-known).

Step-by-Step Resolution

1. Verify Public DNS Records

Let’s Encrypt resolves your domain from the public web. Ensure your domain points to the correct public IP of your VPS. Run a DNS lookup:

dig +short butitworkedlocal.com

Ensure this matches your server’s public IP:

curl ifconfig.me

[!WARNING] If your domain is proxied through Cloudflare (orange cloud icon in the DNS control panel), Let’s Encrypt verification can fail if Cloudflare’s SSL mode is set to “Strict” without a certificate already in place. Temporarily disable the proxy (grey cloud icon) or set Cloudflare SSL to “Flexible” during setup.

2. Open Firewall Ports

Certbot requires port 80 (and 443 for SSL) to be wide open. On Ubuntu, ensure ufw allows this traffic:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

If you are hosted behind a cloud firewall (like AWS, GCP, or a ChicagoVPS network panel), ensure the inbound rules permit external TCP traffic on ports 80 and 443.

3. Fix Web Server Configuration

Ensure your Nginx configuration doesn’t block hidden files. In some hardened configurations, you might have rules that deny files starting with a dot:

# Dangerous rule that blocks Certbot
location ~ /\. {
    deny all;
}

If you have a global deny rule, add an exception block above it specifically for the ACME challenge folder:

location /.well-known/acme-challenge/ {
    allow all;
    root /var/www/html;
}

4. Run Certbot in Webroot Mode

If the automatic Nginx/Apache plugins fail, the most reliable fallback is Webroot Mode. This places the challenge file in a physical folder, and you tell Certbot where to find it.

Create the verification directory manually:

sudo mkdir -p /var/www/html/.well-known/acme-challenge
sudo chown -R www-data:www-data /var/www/html

Run Certbot pointing to that webroot:

sudo certbot certonly --webroot -w /var/www/html -d butitworkedlocal.com -d www.butitworkedlocal.com

Once the certificate generates successfully, configure your Nginx site config to point to the newly created certificates under /etc/letsencrypt/live/butitworkedlocal.com/.