Is this website down or just me? How to check, and what each failure means
How to check if a website is down for everyone or just for you: what a DNS error, a refused connection, a timeout, a certificate error, a 5xx or a 403 each point to, the curl and dig commands that tell them apart, and when a one-off check stops being enough.
Is this website down, or is it just me? To check whether a website is down for everyone, request it from a network that isn't yours and compare the answers. If it loads from somewhere else, the site is up and the problem sits between you and it: your DNS resolver, your ISP, a VPN, the Wi-Fi you're on. If it fails from both, it's very likely down for everyone. The more useful question is where the request dies, because that tells you who has to fix it.
Get a second opinion first
The fastest second opinion is the free “Is it down?” check on this site. It requests the URL from our server in Zurich: a GET, headers only, up to five redirects, and it gives up after 8 seconds. A final status from 200 to 399 counts as “it responded”, a 4xx or 5xx as “it did not respond properly”. If no HTTP response comes back at all, it tells you why: the hostname couldn't be resolved, the connection was refused or reset, the request timed out, or the host was unreachable. That distinction is already half the diagnosis.
The second-fastest is in your pocket. Turn off Wi-Fi on your phone and load the site over mobile data: different ISP, different resolver, different route. If you're on a VPN, turn it off for the test. Then read the two results together:
| Your network | From Zurich | What it usually means |
|---|---|---|
| Fails | Responds | The site is up. Look at your side: DNS cache, hosts file, VPN, proxy, ISP, or the route from your network. |
| Fails | Fails the same way | Down for everyone, or at least for two unrelated networks. Check the site's status page if it has one. |
| Works | Fails | Up for you, broken elsewhere. Often a bot rule or geo-block that refuses datacenter traffic, sometimes a regional outage. |
| Loads, but broken | Responds | The server answers. The problem is in the browser: a failing script, a blocked asset, a certificate your browser rejects. |
Find out where the request dies
Loading a page is four steps in a row: resolve the name, open a TCP connection, negotiate TLS, get an HTTP answer. Each one fails differently, and curl shows you which:
curl -sS -o /dev/null --connect-timeout 5 \
-w 'dns %{time_namelookup}s connect %{time_connect}s tls %{time_appconnect}s first byte %{time_starttransfer}s code %{http_code}\n' \
https://example.comThe times count from the start of the request, so tls minus connect is the handshake. When a step fails, curl prints an error with an exit code. The wording changes between curl versions, the numbers don't:
- (6) Could not resolve host: DNS. Nothing has touched the server yet.
- (7) Failed to connect … Connection refused: the IP answered, but nothing listens on that port, or a firewall actively rejects you.
- (28) timed out: packets go out and nothing comes back. A firewall dropping them, a machine that's off, or a broken route.
- (60) or (35): TLS. 60 means the certificate didn't verify, 35 that the handshake itself failed.
- A 4xx or 5xx code and no error: everything below HTTP works. The server, or something in front of it, answered with an error.
The name doesn't resolve
Ask your own resolver and a public one the same question:
dig example.com # header shows status: NOERROR, NXDOMAIN or SERVFAIL
dig @1.1.1.1 example.com # same question, public resolver
dig +short example.com AAAA # IPv6 address, if there is one
# Windows
nslookup example.com
nslookup example.com 1.1.1.1NXDOMAIN from both means the name doesn't exist: a typo, a deleted record, or a domain that expired. Then it really is down for everyone. SERVFAIL means the resolver couldn't get a valid answer, and broken DNSSEC is the usual suspect. Not every resolver validates, so it can fail on one and work on another. If your resolver and 1.1.1.1 return different addresses after a DNS change, yours is still serving the old record from its cache. The number after the name in the answer section is how many seconds of TTL it has left.
dig asks a DNS server directly, so it skips your hosts file and the browser's own cache. If dig gets the right address and the browser still doesn't, look there: a leftover line in /etc/hosts (on Windows C:\Windows\System32\drivers\etc\hosts) from an old staging setup, or a stale cache. Chrome keeps its own, which you clear under chrome://net-internals/#dns. The operating system's:
# macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Windows
ipconfig /flushdns
# Linux with systemd-resolved
resolvectl flush-cachesConnection refused or timed out
Refused is the better news. Something at that IP answered and said no, which usually means the web server process isn't running or isn't listening on 443. A timeout means nothing answered at all: the machine is off, a firewall drops your packets, or the route is broken somewhere in between. If Zurich gets through and you time out, suspect the route or a blocklist on the server that caught your IP. Also try both IP versions:
curl -4 -sS -o /dev/null -w '%{http_code}\n' https://example.com
curl -6 -sS -o /dev/null -w '%{http_code}\n' https://example.comA site with an AAAA record and a broken IPv6 path works with -4 and hangs with -6. Browsers usually fall back to IPv4 quickly, so you may never notice. Other clients don't always, and your API consumers are among them.
The certificate is rejected
Browsers show this as a full-page warning, curl as exit 60. The three you'll see most are an expired certificate, a name that doesn't match (www.example.com versus example.com), and a missing intermediate certificate. The missing intermediate is the sneaky one: some browsers fetch it themselves or already have it cached, so the site works there and fails in curl, in apps and in other servers calling it.
5xx: the server answered with an error
A 500 comes from the application, a 502 or 504 from a proxy or load balancer that got no usable answer from behind it, a 503 from something overloaded or in maintenance mode. The network path works, and the site is down for everyone who gets routed to that server. Not always everyone, though: behind a load balancer, one bad backend turns into a 502 on every third request. Run the check a few times before you conclude anything. The post on HTTP status codes goes through each of them.
4xx and geo-blocking: up, but not for you
A 403 or 451 is the server telling one particular client no. If your browser gets a 403 and Zurich gets a 200, your IP is the problem: VPN exit nodes and cloud ranges end up on blocklists, and some sites outside the EU simply block European visitors. It also works the other way round. Bot protection often refuses datacenter IPs and unfamiliar user agents, so a 403 from our checker while your browser loads fine means the site is up and filters automated traffic. Our requests identify themselves as HyperMonitors/1.0, which a strict WAF rule may not like.
CDN and edge problems
With a CDN in front of the site you're talking to two servers: the edge location near you and the origin behind it. The response headers tell you who answered. cf-ray means Cloudflare, x-cache and x-served-by show up on many CDNs. Cloudflare's own 52x codes mean the edge is fine and the origin isn't: 521 is the origin refusing the connection, 522 is it timing out. Edge problems tend to be regional, because visitors in Frankfurt and in Singapore hit different edge locations. To take the CDN out of the picture, send the request straight to the origin:
# 203.0.113.10 stands in for your origin's IP
curl -sS -D - -o /dev/null \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/--resolve pins the hostname to that IP but keeps SNI and the Host header, so the origin sees an ordinary request. If that works and the public URL doesn't, the problem is at the CDN. Many origins only accept connections from their CDN, in which case this times out and tells you nothing. And -D - -o /dev/null is deliberate: curl -I is the usual habit, but it sends HEAD, and some applications answer HEAD differently from GET.
It's your side
When Zurich and your phone both load the site and your laptop doesn't, it's local. Roughly in order of how often it's the cause: a VPN or corporate proxy, an ad-blocking DNS (Pi-hole, a filter setting on the router) that has the domain on a list, a browser extension, a cached redirect or HSTS entry from an old setup, a stale hosts entry. A private window rules out extensions and most caches, a second browser most of the rest. If the site works with 1.1.1.1 as resolver and not with your ISP's, the ISP's resolver is broken or blocking the name.
When a one-off check isn't enough
Everything above answers “is it down right now?”. If it's your own site, that question comes too late, because by the time you ask it someone else has noticed first. Problems that come and go, a failure only customers in Asia see, a certificate that expires in nine days: none of that shows up in a check you run once.
A HyperMonitors monitor runs the same kind of request on a schedule. The free plan gives you 5 monitors (HTTP, port or ping), checked every 5 minutes from one region that is picked automatically by measured latency. When a check fails, a probe in a second region re-checks before anyone is alerted, on Free too, so a flaky path between one probe and your server doesn't page you. Solo ($5 a month) checks every minute from up to two regions, Team ($25) from all three: Zurich, New York and Singapore. A monitor with more than one region only goes down when at least two of them agree. One failing region shows as degraded, which is how a regional problem becomes visible without waking you.
Two settings close the gaps this post has been about. A keyword rule, available on Free, fails the check when a page returns 200 but is missing the text it should contain. An SSL monitor, on the paid plans, fails on an expired or untrusted certificate, which an HTTP check doesn't treat as down. And a public status page, one included on Free, answers “is it just me?” for your users before they open a ticket.