Fixing Let’s Encrypt & Certbot Verification Failures (HTTP-01 / DNS-01 Challenges)
Comprehensive troubleshooting guide for Certbot failed to authenticate some domains (HTTP-01 / 403 Forbidden). Learn root causes, system traces, and verified resolutions.
Comprehensive troubleshooting guide for Certbot failed to authenticate some domains (HTTP-01 / 403 Forbidden). Learn root causes, system traces, and verified resolutions.
When attempting to obtain or renew an SSL/TLS certificate using Certbot with Let's Encrypt, encountering an "ACME directory verification failed" error, particularly related to server connection issues, indicates a critical breakdown in the challenge process. This usually means that the Let's Encrypt validation server cannot connect to your server to verify domain ownership, preventing certificate issuance. This guide provides an in-depth, systematic approach to diagnose and resolve these connection-related verification failures on CentOS Stream and Rocky Linux environments.
<!-- Origin Server -->
<rect x="35" y="80" width="190" height="155" rx="6" fill="#151926" stroke="#06b6d4" stroke-width="1.5"/>
<text x="130" y="110" fill="#06b6d4" font-size="14" font-weight="700" text-anchor="middle">Origin Server (Certbot)</text>
<text x="130" y="132" fill="#9ca3af" font-size="11" text-anchor="middle">ACME Client Daemon</text>
<rect x="50" y="150" width="160" height="65" rx="4" fill="#0b0d14" stroke="#2d3748" stroke-width="1"/>
<text x="130" y="172" fill="#67e8f9" font-size="10" font-family="'JetBrains Mono', monospace" text-anchor="middle">/.well-known/acme-challenge/</text>
<text x="130" y="190" fill="#9ca3af" font-size="10" text-anchor="middle">HTTP-01 / DNS-01 Token</text>
<!-- Arrow 1 -->
<path d="M 225 155 L 305 155" stroke="#f59e0b" stroke-width="2" stroke-dasharray="4,4"/>
<text x="265" y="145" fill="#f59e0b" font-size="10" text-anchor="middle">Challenge</text>
<!-- Let's Encrypt CA -->
<rect x="310" y="80" width="180" height="155" rx="6" fill="#151926" stroke="#f59e0b" stroke-width="1.5"/>
<text x="400" y="110" fill="#f59e0b" font-size="14" font-weight="700" text-anchor="middle">Let's Encrypt CA</text>
<text x="400" y="132" fill="#9ca3af" font-size="11" text-anchor="middle">Automated Validation Authority</text>
<rect x="325" y="150" width="150" height="65" rx="4" fill="#0b0d14" stroke="#2d3748" stroke-width="1"/>
<text x="400" y="172" fill="#fde68a" font-size="10" text-anchor="middle">Validates HTTP/DNS Record</text>
<text x="400" y="190" fill="#34d399" font-size="10" text-anchor="middle">Signs X.509 Certificate</text>
<!-- Arrow 2 -->
<path d="M 490 155 L 565 155" stroke="#10b981" stroke-width="2"/>
<text x="528" y="145" fill="#10b981" font-size="10" text-anchor="middle">Issued</text>
<!-- Nginx Proxy -->
<rect x="570" y="80" width="195" height="155" rx="6" fill="#151926" stroke="#10b981" stroke-width="1.5"/>
<text x="667" y="110" fill="#10b981" font-size="14" font-weight="700" text-anchor="middle">Nginx / SSL Termination</text>
<text x="667" y="132" fill="#9ca3af" font-size="11" text-anchor="middle">TLS 1.2 / TLS 1.3 Strict</text>
<rect x="585" y="150" width="165" height="65" rx="4" fill="#0b0d14" stroke="#10b981" stroke-width="1"/>
<text x="667" y="172" fill="#34d399" font-size="10" font-family="'JetBrains Mono', monospace" text-anchor="middle">fullchain.pem + privkey.pem</text>
<text x="667" y="190" fill="#9ca3af" font-size="10" text-anchor="middle">nginx -s reload (post-hook)</text>
Figure 4: Automated SSL certificate issuance and origin reverse proxy reload workflow.
Symptom & Error Signature
Users typically experience this issue when running certbot renew or certbot certonly (or run). The output will show a failure during the challenge phase, often accompanied by messages pointing to network connectivity or server reachability.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator apache, Installer apache
Requesting a certificate for example.com and www.example.com
Certbot failed to authenticate some domains (authenticator: apache). The Certificate Authority reported these problems:
Domain: example.com
Type: connection
Detail: 192.0.2.1: Fetching http://example.com/.well-known/acme-challenge/TOKEN: Connection refused
Domain: www.example.com
Type: connection
Detail: 192.0.2.1: Fetching http://www.example.com/.well-known/acme-challenge/TOKEN: Connection refused
Hint: The Certificate Authority failed to download the temporary file created by Certbot. Ensure that the domain points to this machine's IP address and that your webserver is accessible from the internet.
Some challenges have failed.
Another common variant, especially if the web server is not running or misconfigured for the challenge:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer webroot
Requesting a certificate for example.com
Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
Domain: example.com
Type: unauthorized
Detail: Invalid response from http://example.com/.well-known/acme-challenge/TOKEN [192.0.2.1]: 404
Hint: The Certificate Authority failed to download the temporary file created by Certbot. Ensure that the domain points to this machine's IP address and that your webserver is accessible from the internet.
While the second example shows a 404 (Unauthorized) error, it still stems from the Let's Encrypt server successfully connecting but not finding the file, which can be due to a misconfigured web server or webroot path, or a proxy interfering. The "Connection refused" or "Connection timed out" are direct indicators of server reachability issues.
Root Cause Analysis
The "ACME directory verification failed server connection" error fundamentally means the Let's Encrypt validation servers cannot reach your server over HTTP (port 80) or HTTPS (port 443) to perform the challenge. Several common culprits can lead to this:
Firewall Restrictions:
- Local Firewall (
firewalld):firewalldon CentOS Stream / Rocky Linux might be blocking incoming connections on port 80 (HTTP) or 443 (HTTPS). - Cloud Provider Firewall: Security Groups (AWS), Network Security Groups (Azure), Firewall Rules (GCP), or similar mechanisms at your cloud hosting provider might be blocking access to your instance.
- Upstream/Hardware Firewall: If your server is behind a physical firewall or router, it might be blocking ports.
- Local Firewall (
DNS Resolution Issues:
- Incorrect A/AAAA Records: Your domain's A (IPv4) or AAAA (IPv6) records might be pointing to an incorrect IP address or a server that is not currently online.
- DNS Propagation Delays: Recent DNS changes might not have fully propagated across the internet, causing Let's Encrypt to query an outdated IP.
Web Server Status & Configuration:
- Web Server Not Running: Nginx or Apache HTTPD service might be stopped or failed.
- Incorrect Listener: The web server might not be configured to listen on port 80 (or 443, if using TLS-ALPN-01 challenge, which is less common for initial setup).
- Virtual Host Misconfiguration: The
ServerNameorServerAliasin your virtual host configuration might not match the domain Certbot is trying to validate. - Document Root/Webroot Issues: If using
webrootauthenticator, the specified webroot path might be incorrect, or the web server might not have proper permissions to serve files from that directory.
SELinux Policy Enforcement:
- SELinux (Security-Enhanced Linux) might be preventing your web server process (e.g.,
nginx,httpd) from accessing the temporary files Certbot creates in the webroot or.well-known/acme-challengedirectory.
- SELinux (Security-Enhanced Linux) might be preventing your web server process (e.g.,
Network Connectivity Problems:
- Network Interface Issues: The server's network interface might be down or misconfigured.
- Router/Gateway Problems: Issues with the default gateway or upstream network devices.
- CDN/Proxy Interference: If using a CDN or reverse proxy in front of your server, it might be misconfigured to block the ACME challenge path or redirect it incorrectly.
Let's Encrypt Rate Limits: While less common for connection errors, repeatedly failing challenges can lead to temporary rate limiting, though this typically manifests as specific rate limit errors rather than connection refusals.
Step-by-Step Resolution
Follow these steps systematically to diagnose and resolve the connection issues preventing Certbot verification.
1. Verify DNS Resolution
Ensure your domain points to the correct public IP address of your server.
Identify Your Server's Public IP:
curl ifconfig.me # Or, if you have a public interface configured: ip a | grep -E 'inet .*scope global' | awk '{print $2}' | cut -d/ -f1Query DNS Records for Your Domain:
dig A example.com +short dig AAAA example.com +short # Check AAAA if your server is IPv6 enabled dig A www.example.com +shortCompare the IPs returned by
digwith your server's public IP. They should match.If you recently updated DNS records, allow up to 24-48 hours for full propagation, though usually, it's much faster. You can use online tools like
whatsmydns.netto check global propagation status.
2. Check Firewall Configuration
This is one of the most common causes. Let's Encrypt needs to reach your server on port 80 (for http-01 challenge) or 443 (for tls-alpn-01 challenge).
Local Firewall (
firewalld): CentOS Stream and Rocky Linux usefirewalldby default.List current active zones and services/ports:
sudo firewall-cmd --list-all --zone=publicLook for
httpor80/tcpandhttpsor443/tcpin theservicesorportslist.If port 80 or 443 is missing, add them:
sudo firewall-cmd --zone=public --add-service=http --permanent sudo firewall-cmd --zone=public --add-service=https --permanent sudo firewall-cmd --reloadVerify again:
sudo firewall-cmd --list-all --zone=public
Cloud Provider Firewall / Security Groups: If your server is hosted on a cloud platform (AWS, Azure, GCP, DigitalOcean, Linode, etc.), check its network security configuration.
- AWS: Check associated Security Groups for inbound rules allowing HTTP (port 80) and HTTPS (port 443) from
0.0.0.0/0(anywhere). - Azure: Check Network Security Groups (NSG) inbound security rules.
- GCP: Check Firewall Rules.
- Other VPS providers: Look for "Firewall" or "Network" settings in your control panel.
Ensure that both your local firewall and any cloud provider firewalls are correctly configured. A single blocked port at any layer will cause failure.
- AWS: Check associated Security Groups for inbound rules allowing HTTP (port 80) and HTTPS (port 443) from
Test External Connectivity: From a machine other than your server, try to connect to your domain on port 80.
curl -v http://example.com # Or to test raw port connectivity: nc -vz example.com 80If
curlhangs orncreports "Connection refused" or "Connection timed out", your firewall or network is likely blocking access.
3. Inspect Web Server Status and Configuration
Certbot needs your web server (Nginx or Apache) to be running and correctly configured to serve the ACME challenge files.
Check Web Server Status:
- For Nginx:
sudo systemctl status nginx - For Apache HTTPD:
sudo systemctl status httpd
Ensure the service is
active (running). If not, start it:sudo systemctl start nginx # or httpd sudo systemctl enable nginx # or httpd (to start on boot)- For Nginx:
Test Web Server Configuration Syntax:
- For Nginx:
sudo nginx -t - For Apache HTTPD:
sudo apachectl configtest
Address any syntax errors reported before proceeding.
- For Nginx:
Verify Web Server Listening Ports: Confirm that your web server is listening on port 80 (and 443).
sudo ss -tulnp | grep -E ":80|:443"You should see
nginxorhttpdlistening on0.0.0.0:80(or:::80for IPv6) and potentially0.0.0.0:443.Test ACME Challenge Path (Manual): Certbot places a temporary file in
/.well-known/acme-challenge/. You can manually simulate this.- Create a dummy file:
sudo mkdir -p /var/www/html/.well-known/acme-challenge/ # Adjust path to your webroot echo "test" | sudo tee /var/www/html/.well-known/acme-challenge/testfile - Verify webroot configuration in Nginx/Apache:
Ensure your server block or virtual host for
example.comhas the correctrootdirective (Nginx) orDocumentRoot(Apache).- Nginx Example (
/etc/nginx/conf.d/example.com.confor similar):server { listen 80; server_name example.com www.example.com; root /var/www/html; # Ensure this path is correct # ... other directives ... } - Apache Example (
/etc/httpd/conf.d/example.com.confor similar):<VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/html # Ensure this path is correct <Directory "/var/www/html"> AllowOverride All Require all granted </Directory> # ... other directives ... </VirtualHost>
- Nginx Example (
- Access the test file from your browser or
curl(external connection):
You should seecurl http://example.com/.well-known/acme-challenge/testfiletestas the output. If you get a 404, 403, or connection error, your web server configuration or permissions are likely at fault. Delete the test file afterwards.sudo rm /var/www/html/.well-known/acme-challenge/testfile
If using a CDN or reverse proxy, ensure it's configured to pass through requests for
/.well-known/acme-challenge/directly to your origin server without caching or redirection. Some CDNs offer specific settings for Let's Encrypt validation.- Create a dummy file:
4. Temporarily Disable SELinux (for testing)
SELinux can prevent the web server from reading or writing files in certain directories, especially if Certbot places them in non-standard locations or if your webroot has unusual permissions.
Check SELinux Status:
sestatusIf
SELinux statusisenabledandCurrent modeisenforcing, it might be the cause.Temporarily Set to Permissive Mode:
sudo setenforce 0This changes SELinux to permissive mode, logging but not enforcing policy. Try running Certbot again.
If Certbot succeeds with SELinux permissive: This indicates an SELinux issue. Re-enable enforcing mode immediately:
sudo setenforce 1Then, investigate and apply appropriate SELinux policies rather than leaving it disabled or in permissive mode. Common fixes include:
- Restoring file contexts:
sudo restorecon -Rv /var/www/html # Adjust path to your webroot - Checking boolean settings:
sudo getsebool -a | grep httpd # Common ones: httpd_can_network_connect, httpd_unified # To set: sudo setsebool -P httpd_can_network_connect on - Review your
/var/log/audit/audit.logfor SELinux denial messages (AVCerrors). Useausearchto help interpret these.
Do NOT leave SELinux in permissive or disabled mode permanently on a production server. It is a critical security feature.
- Restoring file contexts:
5. Review Certbot Command & Logs
Double-check your Certbot command and review its detailed logs.
Examine Certbot Command: Ensure the domain names provided to Certbot (
-d example.com -d www.example.com) exactly match the domains configured in your DNS and web server. If you're usingwebroot, ensure the--webroot-pathis correct for the domain.Check Certbot Logs: The most detailed information is in the Certbot logs.
sudo tail -f /var/log/letsencrypt/letsencrypt.log # Look for specific errors or stack traces around the "ACME" or "connection" failure.Use
certbot --dry-run: This command attempts to simulate the certificate issuance process without actually modifying your server or requesting a real certificate, which is useful for testing configurations without hitting rate limits.sudo certbot renew --dry-run # Or for a fresh certificate attempt: sudo certbot certonly --nginx -d example.com --dry-run sudo certbot certonly --apache -d example.com --dry-run sudo certbot certonly --webroot -w /var/www/html -d example.com --dry-run
6. Network Connectivity and Proxies
If all local configurations seem correct, investigate broader network issues.
Traceroute to Let's Encrypt API: Ensure your server can reach the Let's Encrypt validation servers.
traceroute acme-v02.api.letsencrypt.org # Or, if traceroute isn't installed: mtr acme-v02.api.letsencrypt.orgLook for abnormally high latency or dropped packets, which could indicate upstream network problems.
CDN/Reverse Proxy Configuration: If your server is behind a CDN (like Cloudflare) or a reverse proxy (like another Nginx instance, Varnish, HAProxy), ensure it's configured to:
- Pass through requests for
/.well-known/acme-challenge/to your origin server without caching. - Not block requests from the Let's Encrypt validation IP ranges.
Many CDNs have specific settings to handle Let's Encrypt challenges. For Cloudflare, you might need to temporarily disable proxying (set DNS record to "DNS Only" / grey cloud) during renewal if using
http-01challenge, or use their native integration/API for validation (dns-01challenge).
- Pass through requests for
7. Update System and Certbot
Outdated Certbot versions or system packages can sometimes lead to unexpected issues.
Update System Packages:
sudo dnf update -yUpdate Certbot: If Certbot was installed via EPEL or Snap, it should update with
dnf. If installed viapipin a virtual environment, activate the environment and run:pip install --upgrade certbot certbot-nginx # or certbot-apache, certbot-dns-cloudflare, etc.
By systematically working through these steps, you should be able to pinpoint the exact cause of your "Certbot ACME directory verification failed server connection" error and successfully secure your domain.
Multi-Platform Step-by-Step Implementation Matrix
The core underlying mechanism is identical across UNIX distributions, but configuration paths, daemon names, and kernel socket limits differ by platform. Follow the exact instructions for your target operating system below.
🐧 Debian 12 (Bookworm) & Ubuntu 24.04 / 22.04 LTS
On Debian-based systems, systemd service units and standard apt package paths apply:
# Verify active listening sockets and associated process IDs
sudo ss -tulpn | grep -E ":(80|443|3306|5432|6379)"
# Inspect live systemd daemon status
sudo systemctl status --no-pager nginx mysql postgresql redis
🔴 Rocky Linux 9, AlmaLinux & CentOS Stream
On RHEL-derived distributions, remember to check SELinux boolean contexts and firewalld rules:
# Check if SELinux is enforcing and denying network binds
sudo getenforce
sudo setsebool -P httpd_can_network_connect 1
# Open firewall ports
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
🍎 macOS Local Environment (Homebrew)
On macOS, Homebrew services run in user space or launchd:
# Identify processes occupying ports on macOS
sudo lsof -iTCP -sTCP:LISTEN -n -P
# Restart Homebrew services
brew services restart nginx
🪟 Windows WSL2 (Ubuntu / Debian)
On WSL2, port forwarding bridges the Windows host with the WSL virtual adapter. Always ensure host port sharing is not blocked by Windows Fast Startup or native IIS/Hyper-V services:
# Check ports on Windows Host (PowerShell as Admin)
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in 80,443,3306,5432 }
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.