Domain points at your VPS but the site or certificate fails
The domain should reach your server but the site doesn't load, or certbot fails. Check DNS, reachability, the nginx site and the certificate, in that order.
Tested on Ubuntu 24.04 LTS, Debian 13 Stable
Before you start
- A domain you control
- A server running nginx
- Root or sudo access to the server
When a domain that should reach your server doesn't work, the cause is in one of four layers. Check them in this order and stop at the first one that fails: DNS (does the name lead to your server's address?), reachability (do ports 80 and 443 answer?), the site (does nginx serve the right site for that name?), and the certificate.
This page uses example.com for your domain and 203.0.113.42 for your server's address; use your own. Setting the domain up the first time is covered in How to point a domain at your VPS; this page is for when it doesn't work.
1. DNS: does the name lead to your server?
Ask from your own computer, and from a public resolver, so you're not looking at a stale copy:
dig +short NS example.com
dig +short A example.com @one.one.one.one
dig +short AAAA example.com @one.one.one.one(On Windows without dig: nslookup -type=A example.com one.one.one.one.)
- NS: these are the servers that answer for your domain, and the only place where record changes count. If they aren't the provider where you edited the records, your edits have no effect. Edit them where the NS records point, or change the nameservers at your registrar.
- A: must be your server's IPv4 address, exactly, and only that one. An old address here, from a previous server or host, sends visitors and Let's Encrypt to the wrong machine.
- AAAA: if there's an IPv6 record, it must be an IPv6 address your server actually answers on. Browsers and Let's Encrypt try IPv6 first when a domain has one, so a wrong or stale AAAA record breaks things even when the A record is right. Rack4 servers don't have an IPv6 address yet (Check that IPv6 works says when), so a domain pointing at a Rack4 server should have no AAAA record for now. Delete it if there is one.
If you've just changed a record, an answer can stay cached for as long as the record's old TTL. Comparing @one.one.one.one with @dns.google shows whether resolvers have caught up.
2. Reachability: do ports 80 and 443 answer?
From your computer, send a request straight to the server's address, with the domain name attached, so DNS isn't involved:
curl -sI --resolve example.com:80:203.0.113.42 http://example.com/- An HTTP status line (
HTTP/1.1 200,301,404…): the server is reachable. Go to step 3. Connection refused: the address answered, but nothing accepts connections on port 80. Check nginx is running (systemctl status nginx) and listening (sudo ss -ltnp | grep -E ':80|:443'), and that a firewall isn't rejecting the port.- A timeout: nothing answered. A firewall is dropping the traffic:
ufworfirewalldon the server (Check open ports), or the panel firewall. Ports 80 and 443 must both be open for a website, and port 80 for certbot's usual check.
3. The site: is nginx serving the right one?
If the server answers but shows the wrong site, the default "Welcome to nginx" page, or a 404, nginx didn't match your domain to your site. List the names it knows:
sudo nginx -T 2>/dev/null | grep -E 'server_name|listen'Your domain (and www. if you use it) must appear in a server_name line, in a file that's enabled (in /etc/nginx/sites-enabled/ on Ubuntu and Debian). Fix it, then sudo nginx -t && sudo systemctl reload nginx, and repeat the curl --resolve test. A 502 or 504 at this point is a different problem: see Fix nginx 502 and 504.
If you use Cloudflare's proxy (the orange cloud), dig shows Cloudflare's addresses, not yours, and Cloudflare's SSL mode matters too: Full (strict) needs a valid certificate on your server. While you're fixing things, switching the record to DNS only takes Cloudflare out of the picture.
4. The certificate: why certbot failed
certbot proves you control the domain by having Let's Encrypt fetch a file from http://example.com/.well-known/acme-challenge/…. When that fails, certbot prints what Let's Encrypt saw. The Detail: line is the one that matters, and it starts with the address Let's Encrypt connected to. Compare it with your server's address first.
These are the messages we got on a test server:
The name points at another machine:
Domain: example.com
Type: connection
Detail: 198.51.100.7: Fetching http://example.com/.well-known/acme-challenge/…: Connection refusedThe address in Detail: isn't your server's. Fix the A record (step 1), wait for it to spread, then run certbot again.
Port 80 is rejected:
Detail: 203.0.113.42: Fetching http://example.com/.well-known/acme-challenge/…: Connection refusedIt's your address this time, so DNS is right but port 80 refused the connection: nginx isn't listening on it, or a firewall rule rejects it. Fix it as in step 2.
Port 80 is silently dropped:
Detail: 203.0.113.42: Fetching http://example.com/.well-known/acme-challenge/…: Timeout during connect (likely firewall problem)A firewall is dropping traffic to port 80. Open port 80; certbot needs it even if your site redirects everything to HTTPS.
Other messages you may meet:
Type: unauthorizedwithInvalid response … 404: Let's Encrypt reached a web server, but the challenge file wasn't there. Usually the request reached a different site or a different server (a stale A or AAAA record, or a CDN in front), or a redirect rule caught/.well-known/.Type: dnswithNXDOMAINorno valid A records: the name doesn't exist in DNS yet, or has a typo.CAA record … prevents issuance: your domain has CAA records that don't list Let's Encrypt. Check withdig +short CAA example.com; add0 issue "letsencrypt.org"or remove the CAA records.too many certificates already issuedortoo many failed authorizations: you've hit Let's Encrypt's rate limits by retrying. Fix the cause first, and test withcertbot --test-cert, which uses Let's Encrypt's staging service and doesn't count against the real limits.
When it works, certbot says Successfully received certificate. Check what visitors get:
curl -sI https://example.com/ | head -1
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -datesThe subject should name your domain, and the dates should include today.
Renewals that fail later
certbot renews certificates automatically; the same four layers break renewals too, often months later, after a firewall or DNS change. Test the renewal without waiting:
sudo certbot renew --dry-runand fix whatever it reports with the steps above.
We produced the certbot messages on this page on 6 November 2026 on a Rack4 server running Ubuntu 24.04 with nginx 1.24 and certbot 2.9, using Let's Encrypt's staging service: a name pointing at another server, port 80 rejected, port 80 dropped, and a working setup. The "other messages" and the AAAA, CAA and Cloudflare notes come from Let's Encrypt's and Cloudflare's documented behaviour, not from that test.