Loading...

Basics · 7 min read

HTTP status codes: read them as "who refused, and where"

Every reference lists what the codes mean. Almost none say which machine emits them — and on a site behind a CDN, that is the question that shortens debugging from an afternoon to a minute. This is the list from the proxy's point of view.

Güncellendi

HTTP status codes: read them as "who refused, and where"

The classes, briefly

2xx — it worked. 200 OK is the normal answer. 204 No Content is a successful request with nothing to return, common for APIs. 206 Partial Content is a range request, which is how video seeking and resumable downloads work.

3xx — look elsewhere. 301 is permanent and passes ranking signals; 302 is temporary and does not. 304 Not Modified is the quiet one: the client already has a valid copy, so the body is not sent at all. A healthy site serves a lot of 304s.

4xx — the request was refused. 400 is malformed, 401 needs credentials, 403 is a deliberate refusal, 404 is not found, 410 is gone on purpose, 429 is too many requests.

5xx — the server side failed. 500 is an unhandled error, 502 is a broken conversation with the machine behind, 503 is a temporary refusal, 504 is a timeout waiting for the machine behind.

Which hop produced the code

A request behind a CDN passes through at least three places that can answer it: the edge, your origin web server, and your application. Each can produce codes the others cannot.

Only the edge can produce: a cache hit served while the origin is down, a 502 or 504 about your origin, a 403 from a WAF rule or a geographic block, and a 503 saying no service is configured for the hostname.

Only your origin web server produces: 403 from file permissions or a deny rule, 404 for a path that does not exist on disk, 413 for a body larger than it accepts.

Only your application produces: 401 and 403 based on who is logged in, 422 for validation, 500 from an unhandled exception.

So the first diagnostic question is not "what does 502 mean" but "did this request reach my origin at all". If it does not appear in the origin access log, nothing you change on the origin will affect it.

Reading the headers to find the hop

The response tells you who handled it, if you look at the headers rather than the page.

curl -sI https://example.com/

A cache status header — on cdn.com.tr, X-Proxy-Cache-MT with HIT or MISS — means the edge processed the request. A HIT means the origin was not consulted at all, which is worth knowing when you are testing a change and still seeing the old behaviour.

Two traps live here. The first: curl -I sends a HEAD request, and some servers and middleware behave differently for HEAD than for GET, so a header that appears on -I may be absent on a real GET and vice versa. When it matters, use curl -sD - -o /dev/null with a normal GET. The second: a cached error response will keep being served after you fix the cause. If the code does not change after a fix, purge the path before you keep debugging.

The codes worth configuring on purpose

301 vs 302. Use 301 when the move is permanent — it consolidates the old URL's ranking into the new one. A 302 keeps the old URL as the canonical, which is what you want for a temporary campaign redirect and not what you want after a site restructure. Redirects cache at the edge, so a wrong one outlives the deploy that introduced it.

404 vs 410. Both say "not here". A 410 says "and it is not coming back", which gets the URL dropped from the index faster. For retired product pages, 410 is the honest code.

503 with Retry-After. During maintenance, this is the pair that keeps crawlers patient. A maintenance page served with 200 tells them your maintenance notice is your content.

429 for rate limits. More honest than 503 when the refusal is about how fast this client is asking. Not every stack sends it by default — nginx rate limiting returns 503 unless configured otherwise.

The status codes you will actually spend time on

In practice three codes account for most of the debugging time on a site behind a proxy, and each has its own guide:

**502 Bad Gateway** — the edge could not get a usable answer from your origin. Four causes: refused connection, early close, TLS handshake failure, malformed response.

**403 Forbidden** — something refused on purpose. Five possible deciders: your origin, a WAF rule, a country or network block, hotlink protection, an IP list. A reference ID on the error page is what turns guessing into looking it up.

**503 Service Unavailable** — a temporary refusal: overload, maintenance, a rate limit, or an edge with no origin configured for that hostname.

The fourth, 504, is the timeout twin of 502 and is covered in the 502 guide, because telling them apart is most of the work.

HTTP status code FAQ

Which status codes actually affect SEO?

The ones that change what gets indexed: 301 consolidates a URL into its target, 302 does not, 404 and 410 remove a URL with 410 being faster, and a long-running 5xx eventually drops the page. A 200 served on an error page is the quietly damaging one, because the error text gets indexed as content.

Why do I get a different code from curl than from my browser?

The requests differ. Your browser sends cookies, a different user agent and an Accept header; curl usually sends none of those. On a site with a WAF or a login cookie bypass, those differences change the decision. Compare like with like before concluding anything.

Is 304 an error?

No, it is the best outcome after a cache hit: the client already has a valid copy and the server sends no body at all. A lot of 304s in your logs means conditional requests are working.

What does a 000 or empty status mean in my monitoring?

That there was no HTTP response to read: DNS did not resolve, the TCP connection failed, or TLS did not negotiate. It is a connectivity problem rather than an application one, and it is worth distinguishing from a 5xx in whatever alerting you have.