Let's Encrypt HTTP-01 Challenge Fails with Cloudflare Proxy Active
Resolve Let's Encrypt HTTP-01 validation errors when Cloudflare's proxy (orange cloud) is enabled, preventing direct access to your origin server.
Welcome to this technical guide for resolving a common Let’s Encrypt HTTP-01 challenge failure when your domain is actively proxied through Cloudflare. This issue typically manifests as a failure to obtain or renew your SSL certificate, leaving your website with security warnings or inaccessible via HTTPS.
Symptom & Error Signature
When attempting to obtain or renew a Let’s Encrypt certificate using an ACME client like Certbot, you will encounter an error indicating that the HTTP-01 challenge failed. Your website might display browser warnings about an insecure connection (NET::ERR_CERT_COMMON_NAME_INVALID, MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT), or simply fail to load over HTTPS.
The typical error output from Certbot will resemble:
sudo certbot --nginx -d example.com -d www.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Attempting to renew cert (example.com) from /etc/letsencrypt/renewal/example.com.conf produced an unexpected error: Failed authorization procedure. www.example.com (http-01): urn:ietf:params:acme:error:dns :: DNS problem: SERVFAIL looking up A for www.example.com - the domain's nameservers may be malfunctioning. example.com (http-01): urn:ietf:params:acme:error:dns :: DNS problem: SERVFAIL looking up A for example.com - the domain's nameservers may be malfunctioning.
...
Hint: The Certificate Authority failed to download the challenge files.
Please check your firewall and webserver configuration.
Another common variation, especially when Cloudflare is actively proxying, is:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Attempting to renew cert (example.com) from /etc/letsencrypt/renewal/example.com.conf produced an unexpected error: Failed authorization procedure. www.example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://www.example.com/.well-known/acme-challenge/YOUR_TOKEN: Connection refused.
...
Notice the DNS problem or Connection refused for the http-01 challenge, often referencing urn:ietf:params:acme:error:dns or urn:ietf:params:acme:error:connection.
Root Cause Analysis
The core of this problem lies in how the Let’s Encrypt HTTP-01 challenge works and how Cloudflare’s proxy interacts with it.
-
HTTP-01 Challenge Mechanism: To prove you own a domain, Let’s Encrypt’s validation servers attempt to fetch a specific file containing a unique token from
http://yourdomain.com/.well-known/acme-challenge/YOUR_TOKEN. This request must reach your origin web server (e.g., Nginx, Apache) on port 80, where your ACME client (like Certbot) temporarily places the token. -
Cloudflare Proxy (Orange Cloud): When your domain’s A or AAAA records are proxied through Cloudflare (indicated by an orange cloud icon in your Cloudflare DNS settings), all traffic to your domain is routed through Cloudflare’s global edge network. Cloudflare sits between your users and your origin server, providing CDN, WAF, and DDoS protection.
-
The Conflict:
- When Let’s Encrypt’s validators try to access
http://yourdomain.com/.well-known/acme-challenge/YOUR_TOKEN, their DNS lookup foryourdomain.comresolves to a Cloudflare IP address, not your actual origin server’s IP. - The request reaches Cloudflare’s edge servers. Cloudflare, unaware of the specific ACME challenge token that your origin server is trying to present, cannot fulfill this request. It will either serve a cached page, an error, or, if you don’t have an SSL certificate on Cloudflare’s side for that domain yet, it might even fail to establish a connection to your origin securely (if Flexible SSL is not enabled or full strict is active without a cert).
- Consequently, Let’s Encrypt’s validators fail to retrieve the challenge file, leading to the
urn:ietf:params:acme:error:dns(because Cloudflare is effectively acting as the nameserver for the HTTP request) orurn:ietf:params:acme:error:connection(because Cloudflare isn’t passing the challenge correctly to your origin or the connection from Cloudflare to origin fails).
- When Let’s Encrypt’s validators try to access
In essence, Cloudflare’s proxy prevents Let’s Encrypt’s validators from directly communicating with your server to verify domain ownership via the HTTP-01 method.
Step-by-Step Resolution
The most common and effective solution is to temporarily disable Cloudflare’s proxy for the domain(s) you are trying to certify, obtain the certificate, and then re-enable the proxy.
1. Verify Current DNS & Proxy Status
First, confirm that your domain is indeed proxied by Cloudflare and identify your origin server’s IP address.
# Check the A record for your domain
dig +short example.com A
dig +short www.example.com A
If your domain is proxied by Cloudflare, the dig command will return Cloudflare IP addresses (e.g., 104.x.x.x, 172.x.x.x).
Alternatively, check your Cloudflare Dashboard:
- Log in to your Cloudflare account.
- Select your domain.
- Navigate to the DNS section.
- Look at the
Proxy statuscolumn for yourAandAAAArecords. If it shows an orange cloud, it’s proxied. Make note of your actual origin IP address from theContentcolumn.
2. Temporarily Disable Cloudflare Proxy
You need to temporarily bypass Cloudflare’s proxy so that Let’s Encrypt’s validators can directly reach your origin server.
-
In your Cloudflare Dashboard, go to the DNS section.
-
For each
AandAAAArecord associated with the domain(s) you are trying to certify (e.g.,example.com,www.example.com), click the orange cloud icon to change it to a grey cloud (DNS Only).- This means traffic will now go directly to your origin server’s IP address.
[!IMPORTANT] Disabling the Cloudflare proxy will temporarily expose your origin server’s IP address to the public internet. Ensure your server’s firewall is correctly configured to only allow necessary inbound connections (e.g., SSH on port 22, HTTP on port 80, HTTPS on port 443).
-
Allow a few minutes for DNS changes to propagate. While Cloudflare’s DNS changes are usually instant, some clients might still cache old DNS records. You can verify the change with
digagain; it should now return your origin server’s IP.
3. Ensure Nginx/Web Server is Prepared for Challenge
Before running Certbot, ensure your web server (Nginx in this guide) and server’s firewall are configured to allow direct access to port 80.
-
Check Firewall (UFW): Ensure port 80 is open on your server.
sudo ufw status verboseIf
80/tcpis not allowed, enable it:sudo ufw allow 'Nginx HTTP' sudo ufw reload -
Nginx Configuration: Certbot’s
--nginxauthenticator plugin usually handles creating a temporary configuration for the/.well-known/acme-challenge/path. However, it’s crucial that your Nginxserverblock for the domain in question is listening on port 80.Verify your Nginx configuration, typically in
/etc/nginx/sites-available/yourdomain.com:server { listen 80; listen [::]:80; server_name example.com www.example.com; # Ensure no aggressive HTTP to HTTPS redirects here for the challenge to work. # If you have a 'return 301 https://$host$request_uri;' for port 80, # comment it out temporarily, or add an exception for /.well-known/acme-challenge/ location /.well-known/acme-challenge/ { root /var/www/html; # Or wherever your webroot is } # Other locations... }[!WARNING] If you have an existing Nginx configuration that aggressively redirects all HTTP traffic to HTTPS (e.g.,
return 301 https://$host$request_uri;directly within the port 80 server block, before anylocation /.well-known/acme-challengedirective), Certbot’s HTTP-01 challenge will fail. Temporarily comment out or modify such redirects to allow the challenge path on port 80. Certbot typically adds its own temporary configuration, but this can interfere.Test your Nginx configuration for syntax errors and reload if you made changes:
sudo nginx -t sudo systemctl reload nginx
4. Run Certbot to Obtain/Renew Certificate
With Cloudflare proxy disabled and your server ready, run Certbot.
-
Obtain a new certificate:
sudo certbot --nginx -d example.com -d www.example.comReplace
example.comandwww.example.comwith your actual domain(s). -
Renew an existing certificate (if it’s just about to expire):
sudo certbot renew --force-renewalUsing
--force-renewalis generally discouraged for regular use due to rate limits, but can be useful for immediate troubleshooting when you know the environment has changed. Otherwise, a simplesudo certbot renewshould work.
Certbot will communicate directly with your Nginx server, place the challenge file, and Let’s Encrypt’s validators will now be able to retrieve it from your origin IP. If successful, Certbot will output a success message and usually offer to configure Nginx to use the new certificate and set up redirects.
5. Re-enable Cloudflare Proxy
Once Certbot confirms the certificate has been successfully obtained or renewed:
-
Return to your Cloudflare Dashboard and the DNS section.
-
For the
AandAAAArecords you previously changed, click the grey cloud icon to turn it back to an orange cloud (Proxied).[!IMPORTANT] Re-enabling the proxy is crucial to restore Cloudflare’s security, performance, and caching benefits for your website. Do not skip this step!
Your website will now serve content through Cloudflare’s network with your newly issued Let’s Encrypt SSL certificate installed on your origin server. Cloudflare will also automatically provision its Universal SSL certificate for your domain on its edge network, completing the end-to-end encryption.
6. (Optional/Advanced) Use DNS-01 Challenge with Cloudflare API
For a more automated and robust solution, especially for environments where temporarily disabling Cloudflare proxy is problematic or for domains not serving web content on port 80, consider using the DNS-01 challenge. This method proves domain ownership by creating a specific TXT record in your domain’s DNS.
This requires:
- Certbot Cloudflare DNS Plugin:
certbot-dns-cloudflare. - Cloudflare API Token: A token with appropriate permissions to modify DNS records for your domain.
-
Install the plugin:
sudo apt update sudo apt install python3-certbot-dns-cloudflare -
Create Cloudflare API Token:
- Log in to Cloudflare.
- Go to My Profile > API Tokens > Create Token.
- Use the “Edit Cloudflare DNS” template or create a custom token with:
- Permissions: Zone > DNS > Edit
- Zone Resources: Include > Specific zone > [your domain]
- Save the token securely.
-
Create API Credentials File: Create a file like
/etc/letsencrypt/cloudflare.iniwith your token:dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKENSecure the file:
sudo chmod 600 /etc/letsencrypt/cloudflare.ini -
Run Certbot with DNS-01 Challenge:
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini -d example.com -d www.example.comThis method does not require disabling the Cloudflare proxy and is excellent for full automation.
7. (Optional) Troubleshooting Nginx Configuration
If after unproxying Cloudflare and checking your firewall, Certbot still fails, the issue might be with Nginx’s ability to serve the challenge file.
-
Temporary Manual Test: Manually create a test file:
sudo mkdir -p /var/www/html/.well-known/acme-challenge/ echo "test" | sudo tee /var/www/html/.well-known/acme-challenge/testfileTry to access it from your browser (or
curlfrom a different machine/VPN):http://example.com/.well-known/acme-challenge/testfileIf this fails (e.g., 404 Not Found), your Nginx configuration for the webroot or the.well-knownpath is incorrect. -
Ensure Correct Webroot: Make sure your Nginx
serverblock’srootdirective points to the correct directory wherecertbotwill place its challenge files. If you use a different webroot (e.g.,/var/www/yourdomain), adjust therootdirective or ensurecertbotis configured to use the correct path. When usingcertbot --nginx, it usually attempts to deduce the correct webroot.
By following these steps, you should successfully resolve the Let’s Encrypt HTTP-01 challenge failure caused by an active Cloudflare proxy and secure your website with a valid SSL certificate.
