521
Cloudflare's own code, not an IETF one, for the narrowest failure in the whole 5xx range: your origin actively refused Cloudflare's TCP connection, so nothing was slow and nothing was misrouted — something said no.
The same three digits are three different problems depending on which side of the request you are on. Read the block that describes you.
Why you are seeing it
There is nothing here for you, and confirming that quickly is the contribution. Every request to the zone fails identically and instantly — the HTML document, the API, the hashed asset bundle, all of it — because the failure happens before any of your application's code exists in the picture. What you are looking at is Cloudflare's own HTML page, carrying a `server: cloudflare` header and a `cf-ray`, and it will trip any `res.json()` in your client with a parse error on `<`.
What to do
Establish that it is site-wide, because that single fact reroutes the whole investigation: a 521 on one path is not really a 521, it is your origin's own response being relayed, and a genuine 521 takes down the static assets too. Then collect the two strings that matter — the `cf-ray` value from the response headers, and the exact time — and hand them over, because those are what an operator uses to find the request on Cloudflare's side. Stop the client from making it worse: an automatic retry loop against a refused origin achieves nothing and delays recovery, so cap retries hard. And do not spend time on CORS, even though the console will show a CORS error: an error page carries no `access-control-allow-origin`, so the browser stacks a CORS complaint on top of the real failure and the CORS message is the symptom.
Why you are seeing it
Something on the origin sent Cloudflare a refusal rather than a handshake, and there are only three candidates. The process is not running or crashed, so nothing holds the socket. The process is running but bound to the wrong interface — an application on `127.0.0.1:8080` refuses every connection from outside as completely as a stopped one does. Or a firewall is rejecting Cloudflare specifically, which is the case that appears without a deploy: fail2ban, a new security group rule, or a host-based blocker that banned an address range after seeing all traffic arrive from a handful of proxy addresses.
What to do
Check in that order, because each check is cheap and each one excludes the next. Is anything listening — `ss -ltnp` on the origin — and is it bound to `0.0.0.0` rather than to loopback? Is it on the port your SSL/TLS mode requires: Cloudflare documents port 80 for Flexible and port 443 for Full and Full (Strict), and Cloudflare only proxies its published port list at all, so a service on 3000 is invisible to it. Is Cloudflare allowed in? Cloudflare's documented fix is to allow all of its IP ranges in the origin firewall or security software, and to confirm its addresses are neither blocked nor rate limited — rate limited matters as much as blocked, since proxied traffic concentrates a whole site's requests into a small set of source addresses that look exactly like an attack to a naive rule. Then read the origin's own error log for a crash, which Cloudflare also lists, and note the asymmetry that makes this diagnosable: a firewall set to REJECT produces 521, while the same firewall set to DROP produces 522, so the code tells you which rule you are looking for.
Why you are seeing it
The page you are reading was written by Cloudflare, which sits in front of the website and is working fine; the website's own server behind it is not accepting connections. Nothing about your browser, your device or your network is involved — the same page appears for everyone, everywhere, and it appears immediately rather than after a wait. It usually means the site's server has stopped or has been misconfigured, and it typically lasts until somebody notices.
What to do
There is genuinely nothing to try locally: reloading, clearing cookies, switching browsers, changing DNS or restarting the router cannot make a remote server accept connections. Wait a few minutes and reload once. If you need to report it, the Ray ID printed at the bottom of the Cloudflare page and the exact time are the two things worth sending, because they identify the exact request in the site operator's records. For a paid service, the status page or the operator's social account is the fastest way to learn whether they already know, and a 521 is the kind of failure that gets noticed quickly because it affects every visitor at once.
Run this against the URL that failed. It prints the status without the error page, so you can see what the server said rather than what the browser rendered.
curl -sS -o /dev/null --connect-timeout 5 -w '\n%{http_code} connect=%{time_connect}s\n' --resolve example.com:443:203.0.113.10 https://example.com/`--resolve` makes curl connect to the address you name while still sending the original host name and SNI, so this reproduces what Cloudflare does when it dials your origin, with the edge taken out of the path — put your real origin address in place of the example one. `--connect-timeout 5` keeps a refusal fast and, just as usefully, separates it from a silent drop. There are three outcomes and each is a different bug. `curl: (7) Failed to connect to example.com port 443: Connection refused` is the reproduction: the origin refused you exactly as it refused Cloudflare, and the answer is on the origin — no listener, wrong bind address, wrong port, or a firewall set to reject. A hang that ends at the five-second connect timeout is not a 521 at all; a dropped SYN is what Cloudflare reports as 522, so a DROP rule and a REJECT rule on the same firewall produce two different error numbers. And a normal response means the origin accepts connections from you but not from Cloudflare, which points squarely at source-address filtering rather than at the service — check the origin firewall against Cloudflare's published IP ranges. Run the same request without `--resolve` afterwards to see the edge's answer and read the `cf-ray` header, which is the id an operator can look up.
521 is not in RFC 9110. The IETF's registered 5xx codes stop at 511, and the 520-526 range is Cloudflare's own extension, documented only by Cloudflare and produced only for traffic proxied through it — a DNS record that is grey-clouded cannot return one. Cloudflare defines the code exactly: error 521 occurs when the origin web server refuses connections from Cloudflare. That word "refuses" is the entire value of the number. A refusal is an answer — a TCP RST, or an ICMP unreachable — which means the packet reached the origin's network and something there declined it, and that rules out three neighbouring codes in one step. It is not 522, which Cloudflare defines as a timeout: no SYN+ACK within 19 seconds of Cloudflare's SYN, or no acknowledgement of the request within 90 seconds after the connection is established. It is not 523, which Cloudflare defines as being unable to contact the origin at all, typically because a network device between them has no route to the origin's address. And it is not 520, which is the origin answering with something empty, unknown or unexpected. Cloudflare lists two causes for 521 — an offlined origin web server application, and blocked Cloudflare requests — and the resolutions follow from them: ensure the origin is responsive, review its error logs for application crashes or outages, confirm Cloudflare's IP addresses are not blocked or rate limited, allow all Cloudflare IP ranges in the origin's firewall or other security software, and ensure the origin is actively bound and listening on the port your SSL/TLS mode requires — port 80 for Flexible, port 443 for Full and Full (Strict). That last item catches the case people spend longest on, because Cloudflare only proxies a fixed set of ports: 80, 8080, 8880, 2052, 2082, 2086 and 2095 for HTTP, and 443, 2053, 2083, 2087, 2096 and 8443 for HTTPS. An origin listening anywhere else is unreachable by the proxy no matter how healthy it is.
| Confused with | How to tell them apart |
|---|---|
522 | Both mean Cloudflare could not get a working connection to your origin, and the difference is whether the origin answered. 521 is a refusal, which is an answer and therefore instant. 522 is a timeout, which Cloudflare defines precisely: no SYN+ACK within 19 seconds of its SYN, or no acknowledgement of its request within 90 seconds after the connection is up. The same firewall rule produces one or the other depending on REJECT versus DROP. |
523 | 523 is Cloudflare being unable to contact the origin at all, which its documentation attributes to a network device between them having no route to the origin's address. Their worked example is an AWS route table where an over-broad `172.0.0.0/8` entry swallows Cloudflare's own `172.64.0.0/13` range and sends the return traffic somewhere private. So 521 means the packets arrived and were refused; 523 means they never got there. |
520 | 520 is the origin answering with something Cloudflare cannot use — empty, unknown or unexpected, including response headers above Cloudflare's 128 KB limit, which excessive cookies reach more often than people expect. That is the opposite end of the connection from 521: with 520 the handshake, the request and a response all happened, and only the content of the response was wrong. |
| 502 | 502 is the IETF code any proxy may return for an invalid response from an inbound server, and it covers refusals, resets and unparseable replies all at once. 521 is Cloudflare narrowing that same class down to one cause, which is the reason the 520-526 range exists: a generic 502 leaves you checking four things, while a 521 tells you the origin refused the connection and sends you straight to the listener and the firewall. |
| 524 | 524 is the reassuring one by comparison, because it proves the connection succeeded: Cloudflare connected to the origin and then waited 125 seconds for an HTTP response that never came. So 524 rules out every question 521 raises — the listener is up, the port is right, the firewall is letting Cloudflare through — and moves the whole investigation into the application. |
All of these run in your browser — nothing is uploaded.
Codes people usually end up reading in the same session as 521.
Read the response headers rather than the page. curl -sS -o /dev/null -D - https://example.com/path prints them without the body, and server, via and cf-ray between them name the layer that answered. A cf-ray value means Cloudflare handled the response and is the id their support will ask for. To take the edge out of the picture entirely, repeat the request with --resolve example.com:443:203.0.113.10, which connects to the origin address you name while still sending the original host name and SNI — if the answer changes, the edge and the origin disagree.
No, and you should never branch on it. RFC 9112 tells clients to ignore the reason phrase, servers are free to change it, and HTTP/2 and HTTP/3 do not carry one at all — so 404 Not Found over HTTP/1.1 arrives as a bare 404 over HTTP/2. The phrases on this site are the registered ones because they are what people search for and what appears in an HTTP/1.1 log, not because any software depends on them.
Retry 5xx and 429; do not retry 4xx, because nothing about the request will be different next time. If the response carries Retry-After, honour it — RFC 9110 defines it for exactly this, and it may be either a number of seconds or a date. Otherwise use exponential backoff with jitter and a hard cap, and only for idempotent methods: a retried POST can charge a card twice. A retry storm against a server that is already failing is how a brief incident becomes a long one.
Yes, and the only rule that matters is that the code has to be true. Anything that reads your responses automatically — search engines, monitoring, caches, client retry logic — makes decisions from the number and never from the page. Serving an error page with 200 hides the failure from your own alerting; serving 200 for a missing page gets the error indexed as content; returning 500 for a request that was simply malformed sends whoever is on call to the wrong half of the stack.
Still stuck on 521? browse every status code in the reference — or go back up to the block written for your side of the stack.