Why Is My Site Down? A Field Guide to Failure Causes
"The site is down" is not a diagnosis. A DNS failure, an expired certificate and a crashed PHP process all look the same to a visitor, but they have different causes, different first commands and often different people who can fix them. This field guide goes through each failure type that Uptime Monitor records for a failed check: what it means, what usually causes it in practice, the first command to run, and who normally owns the fix.
Read the cause before you open a terminal
Every failed check in Uptime Monitor is tagged with a cause code, and each check also records a timing breakdown: DNS lookup time, TCP connect time, TLS handshake time, time to first byte and total time. Together they tell you how far the request got. The dashboard shows the cause for each check and, when the site is slow, names the phase that is the likely bottleneck; PDF reports on Plus and Professional show the average time per phase. A check that failed in DNS never reached your server; a check with fast DNS, connect and TLS but a 30-second wait for the first byte reached your application and stalled there. Screenshots taken when the site goes down show what a visitor saw. That is often enough to tell an error page from a blank page from a hosting provider's suspension notice.
The cheat sheet
| Cause code | Meaning | Most common causes | First command | Usually owned by |
|---|---|---|---|---|
dns_error | Hostname could not be resolved | Expired domain, wrong nameservers, deleted record, DNS provider outage | dig example.com +trace | Whoever controls the domain and DNS |
connect_error | TCP connection to the server failed | Web server stopped, firewall change, server or network down, wrong IP in DNS | curl -v https://example.com | Server or hosting admin |
ssl_error | TLS handshake or certificate problem | Expired certificate, missing intermediate, hostname mismatch | openssl s_client -connect example.com:443 -servername example.com | Server admin |
timeout | No complete response within the time limit | Saturated worker pool, slow database query, slow external API, overloaded server | curl -o /dev/null -s -w '%{time_starttransfer}\n' https://example.com | Developers and server admin |
no_response | Connection opened but no valid HTTP response came back | Crashed worker, proxy misconfiguration, connection reset | curl -v https://example.com | Server admin |
server_5xx | Server returned 500–599 | Application error (500), dead upstream (502), maintenance or overload (503), upstream timeout (504) | tail -n 50 /var/log/nginx/error.log | Developers (500) or server admin (502/504) |
not_found_404 | Server returned 404 | Changed route, wrong document root, deleted page, wrong vhost | curl -I https://example.com/path | Developers or content owner |
client_4xx | Other 4xx (401, 403, 429…) | WAF or rate limiter blocking the monitor, added authentication, IP restrictions | curl -I -A "Mozilla/5.0" https://example.com | Whoever manages the WAF/CDN or auth |
redirect_3xx | Redirect received where a final page was expected | Redirect added, follow-redirects turned off in the monitor, HTTP-to-HTTPS rule | curl -sI https://example.com | grep -i location | Developers or server admin |
redirect_error | Redirects could not be followed | Redirect loop, too many hops, redirect to an invalid URL | curl -sIL --max-redirs 10 https://example.com | Developers or server admin |
keyword_missing | Page loaded but the required text was not in the body | Bad deploy, error page served with 200, empty data, CMS edit, bot challenge page | curl -s https://example.com | grep -c "Your keyword" | Developers or content owner |
maintenance | Check fell inside a maintenance window | Planned work | None | Nobody; expected |
DNS errors
A dns_error means the monitor could not turn the hostname into an IP address, so the request never left for your server. Restarting anything on the server is pointless. The usual causes, roughly in the order worth checking: the domain expired; nameservers were changed at the registrar during a hosting move; a record was deleted or mistyped in the DNS panel; the DNS provider itself is having an outage. Start with:
dig example.com +trace
dig example.com @1.1.1.1
whois example.com | grep -i -E 'expir|status'
+trace walks the delegation from the root servers, so you can see whether it breaks at the TLD (registrar or nameserver problem) or at your own nameservers (zone problem). The owner is whoever controls the registrar and DNS account, which at small companies is often a person who has left. Find out who that is before you need to know. The article on DNS latency and its impact on speed covers the resolution path in more depth.
Connection errors and empty responses
connect_error means DNS worked but a TCP connection to port 80 or 443 failed: refused (nothing listening), or no reply at all (a firewall dropping packets, the server down, or a routing problem). no_response means the connection opened and then closed or reset without a valid HTTP response. That usually points at a process that accepted the connection and died, or a reverse proxy pointing somewhere broken.
curl -v https://example.com # where exactly does it stop?
ss -ltnp | grep -E ':(80|443) ' # on the server: is anything listening?
systemctl status nginx --no-pager
sudo ufw status # or: sudo iptables -S / nft list ruleset
If the server is reachable over SSH but nothing listens on 443, the web server is stopped or failed to start after a config change (nginx -t shows why). If SSH is unreachable too, the problem is the host or the network, and the hosting provider's status page and console come next. Uptime Monitor checks from a single location, so a brief connect_error can occasionally be a network path problem between the monitor and your host rather than your server. A failure that persists through the fail threshold is very unlikely to be that.
SSL errors
ssl_error means the TLS handshake failed or the certificate was rejected. In practice: the certificate expired because automatic renewal broke; an intermediate certificate is missing (browsers sometimes cope, strict clients do not); the certificate does not cover the hostname (for example www is missing); or a new server was set up with a self-signed default certificate.
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Check notAfter, whether the hostname appears in the subject alternative names, and whether the issuer is the CA you expect. On Let's Encrypt setups, sudo certbot certificates and sudo certbot renew --dry-run show whether renewal works. See why SSL certificate monitoring matters for catching this before it becomes an outage.
Timeouts
A timeout means the server did not finish answering in time. The timing breakdown narrows it down: slow connect points at the network or an overloaded host; fast connect but a very long time to first byte points at the application. Common causes are a PHP-FPM or app worker pool where every worker is busy, a slow database query (often after data growth or a missing index), a call to an external API that hangs without a timeout, or the server running out of memory and swapping.
curl -o /dev/null -s -w 'dns %{time_namelookup} connect %{time_connect} tls %{time_appconnect} ttfb %{time_starttransfer} total %{time_total}\n' https://example.com
grep -i 'max_children' /var/log/php8.3-fpm.log | tail
uptime; free -m
"server reached pm.max_children setting" in the PHP-FPM log means requests are queueing behind busy workers; the question is what the workers are waiting on. The slow query log or your APM tool answers that. Timeouts are usually a shared problem between developers (slow code, missing timeouts on outbound calls) and whoever sizes the server.
Server errors (5xx)
The specific status matters more than the class:
- 500 Internal Server Error: the application threw an exception. Look in the application log (
storage/logs/laravel.log, the PHP error log, your framework's equivalent). Developers own this. - 502 Bad Gateway: nginx or a load balancer could not get a valid response from the upstream app. The app process is down, crashed or listening on a different socket. The nginx error log says
connect() failedorupstream prematurely closed connection. See 502 Bad Gateway: causes and fixes. - 503 Service Unavailable: maintenance mode, an overloaded upstream, or a load balancer with no healthy backends. Check whether someone ran a maintenance command before restarting anything.
- 504 Gateway Timeout: the upstream accepted the request but did not answer before the proxy gave up. It is a timeout in disguise; diagnose it the same way.
sudo tail -n 50 /var/log/nginx/error.log
sudo journalctl -u php8.3-fpm --since "15 min ago" --no-pager
404 and other 4xx responses
not_found_404 on a URL that used to work almost always follows a change: a deploy that renamed routes, a server move with a different document root, a vhost that lost its server_name so requests land on the default site. Compare curl -I against the hostname with what you expect, and check which server block answered.
client_4xx covers the rest. A 403 or 429 that appears without any change on your side is very often a WAF, CDN or rate limiter deciding the monitor looks like a bot. That is the site working as configured, not down; allowlist the monitor or adjust the rule. A 401 means authentication was added. If that is intended, add HTTP Basic Auth credentials or accept 401 as an "up" status in the site settings.
Redirect problems
redirect_3xx means the check got a redirect where it expected a final page, usually because follow-redirects is turned off for that site or a new redirect was added. Either enable following or add the status code to the accepted list if the redirect is intentional. redirect_error means the chain could not be completed, most often a loop: an HTTP-to-HTTPS rule on the server fighting an HTTPS-to-HTTP rule at the CDN, or www and apex redirecting to each other. curl -sIL prints every hop so the loop is visible.
Keyword missing
The page returned a normal status, but the text you told the monitor to look for was not in the body. This catches failures status codes miss: a PHP warning page served with 200, an empty product list because a database table was truncated, a theme update that removed the footer, a bot-challenge page from your CDN. Fetch the page as the monitor does and look at what is actually there:
curl -s https://example.com | head -c 2000
Choose keywords that only appear when the page truly works, such as text rendered from the database rather than in the static header. Keyword monitoring for pages that return 200 OK covers how to pick them.
Maintenance
maintenance marks checks that fell inside a scheduled maintenance window. No request is sent to the site, and no alerts or automated actions run. If you see it outside planned work, check the window's recurrence settings, especially windows that span midnight.
Checklist
- Read the cause code and timing breakdown before touching the server.
- DNS, SSL and 4xx causes are rarely fixed by restarting anything.
- For 5xx, the exact status (500 vs 502 vs 503 vs 504) decides where you look.
- Know who owns DNS, the CDN/WAF and the server before an outage.
- Use screenshots to see what visitors saw.
Uptime Monitor records the cause code, the timing breakdown and a screenshot for state changes, and webhook alerts carry it as cause_code and cause_summary so your own tools can route on it. Your first look at a failure tells you where to start. You can monitor a site for free with checks every five minutes, or go down to one-minute checks on Professional.