Fix Let's Encrypt "Type: unauthorized" Error โ€” Certbot Renewal Failed

intermediate๐Ÿ”’ SSL/TLS2026-03-18| Linux (Ubuntu 20.04/22.04, Debian 11/12, CentOS 7/8), Nginx or Apache, Certbot 1.x/2.x

Error Message

Certbot failed to authenticate some domains. The following errors were reported: Domain: example.com Type: unauthorized
#ssl#letsencrypt#certbot#renewal

TL;DRThe Type: unauthorized error means Certbot's HTTP-01 challenge failed โ€” Let's Encrypt couldn't fetch a temporary token file from http://yourdomain.com/.well-known/acme-challenge/. Run this first:

curl -I http://yourdomain.com/.well-known/acme-challenge/test

Connection refused? Your web server isn't running or port 80 is blocked. Got a 404? The server is up but something's intercepting the request path. 404 vs timeout tells you immediately which rabbit hole to go down.

What's Actually HappeningLet's Encrypt proves you own a domain through the HTTP-01 challenge: Certbot writes a short token file under /.well-known/acme-challenge/, and Let's Encrypt's servers reach out over plain HTTP to read it back. That exchange happens on Let's Encrypt's end โ€” you have no control over it once renewal starts. If the fetch fails for any reason, you get Type: unauthorized.

Six things cause this the vast majority of the time:

  • Port 80 blocked โ€” firewall or cloud security group dropping inbound HTTP- Web server not running โ€” Nginx/Apache crashed, or a recent config change left it stopped- DNS mismatch โ€” the domain resolves to a different IP than this server- Server config intercepting .well-known โ€” a blanket HTTPS redirect catches the challenge request before it reaches the file- Cloudflare proxy โ€” the orange-cloud proxy mode sometimes terminates HTTP before the challenge token is served- CAA DNS record โ€” explicitly restricts which certificate authorities can issue certs for your domain## Step-by-Step Fixes### Step 1 โ€” Confirm port 80 is reachableRun this from a different machine (or use an online port checker like portchecker.co):
nc -zv yourdomain.com 80

If it times out or says refused, open the port:

# UFW (Ubuntu/Debian)
sudo ufw allow 80/tcp
sudo ufw reload

# firewalld (CentOS/RHEL)
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --reload

# iptables direct
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT

Running on AWS, GCP, or Azure? The cloud security group sits outside the OS entirely. Open port 80 there too โ€” the console won't show it as blocked, but it is.

Step 2 โ€” Make sure your web server is running```

Nginx

sudo systemctl status nginx sudo systemctl start nginx

Apache

sudo systemctl status apache2 sudo systemctl start apache2


Check `journalctl -u nginx -n 50` if the service won't start โ€” a config syntax error from a recent edit is a common culprit.
### Step 3 โ€” Check DNS points to this server```
dig +short yourdomain.com
curl -s ifconfig.me

Both should return the same IP. If they don't, update the A record at your DNS provider and wait. With a TTL of 300 seconds, propagation takes 5โ€“10 minutes. With a 3600 TTL, budget an hour. Don't retry Certbot until they match.

Step 4 โ€” Fix Nginx blocking the challenge pathA blanket HTTPโ†’HTTPS redirect will intercept the challenge before it ever touches the file. The fix is a location block that short-circuits the redirect for the challenge path only:

server {
    listen 80;
    server_name yourdomain.com;

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

    location / {
        return 301 https://$host$request_uri;
    }
}
sudo nginx -t && sudo systemctl reload nginx

Step 4b โ€” Fix Apache blocking the challenge path```

<VirtualHost *:80> ServerName yourdomain.com

Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
    Options None
    AllowOverride None
    Require all granted
</Directory>

Redirect permanent / https://yourdomain.com/
sudo apachectl configtest && sudo systemctl reload apache2

Step 5 โ€” Check CAA DNS records```

dig CAA yourdomain.com


No output? You're fine โ€” no CAA records means any CA can issue. If you do have them and `letsencrypt.org` isn't in the list, add it:

yourdomain.com. 3600 IN CAA 0 issue "letsencrypt.org"


### Step 6 โ€” Cloudflare usersCloudflare's orange-cloud proxy mode can terminate HTTP before your server serves the challenge token. The quickest fix: flip the DNS record to grey-cloud (DNS only) in the Cloudflare dashboard, wait 60 seconds, renew, then flip it back.
Rather not touch the proxy? Use the DNS-01 challenge with Cloudflare's API instead โ€” no HTTP involved at all:

sudo apt install python3-certbot-dns-cloudflare sudo certbot certonly
--dns-cloudflare
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini
-d yourdomain.com


### Step 7 โ€” Run a dry run with verbose outputDon't go straight to a real renewal. Let's Encrypt rate-limits failed attempts (5 failures per domain per hour), so burn a dry run first:

sudo certbot renew --dry-run --verbose


The verbose output shows the exact URL Certbot tries to validate and what HTTP response it got back โ€” far more useful than the default one-liner error. Once the dry run passes cleanly, run the real thing:

sudo certbot renew


### Bonus โ€” Use standalone mode to isolate the problemWant to completely rule out your server config? Stop the server and let Certbot spin up its own temporary HTTP listener on port 80:

sudo systemctl stop nginx sudo certbot certonly --standalone -d yourdomain.com sudo systemctl start nginx


Works with standalone but fails normally? Your server config is the problem, full stop. DNS and firewall are both fine.
## Verify the Fix Worked```
# List all certificates and expiry dates
sudo certbot certificates

# Check the cert directly via OpenSSL
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null \
  | openssl x509 -noout -dates

# Confirm HTTPS responds
curl -I https://yourdomain.com

The notAfter date should sit roughly 90 days out from today. If certbot certificates shows a future expiry, you're done.

Keep It From Breaking AgainPort 80 must stay open permanently โ€” even on sites that redirect everything to HTTPS. Let's Encrypt hits it every 60โ€“90 days for renewal. Block it and you'll be back here.

Next, confirm auto-renewal is scheduled:

# Check the systemd timer (modern Certbot installs)
systemctl list-timers | grep certbot

# Or check cron
crontab -l | grep certbot

Nothing shows up? Add a cron job manually:

sudo crontab -e
# Add:
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

The --post-hook is worth noting: it only fires when a certificate is actually renewed, not on every run. Your server won't get an unnecessary reload at 3am on the 364 days a year nothing changes.

Related Error Notes