Quick Summary – Cloudflare Error 521
Cloudflare error 521 is associated with the origin web server refusing Cloudflare's connection. A stopped service or blocked Cloudflare addresses are common causes; the error code alone does not identify which one occurred.
- Origin address — Verify the A and any AAAA targets in the Cloudflare DNS dashboard; public DNS responses for a proxied record do not reveal the origin address.
- HTTPS listener — In this Full (strict) scenario with no port override, check that Nginx listens on TCP 443 on an address that accepts external connections.
- Direct connection — Use curl –resolve from an authorized external test location to test the origin IP while preserving the hostname, SNI, and certificate verification.
- Firewall rules — Check that server and provider rules grant the required access to Cloudflare's current IPv4 and IPv6 ranges.
- TLS distinctions — While 521 is associated with connection refusal, 525 indicates a TLS handshake failure and 526 indicates a certificate validation failure in Full (strict) mode.
- Final verification — Test the fix through Cloudflare using a response confirmed not to come from cache; a successful cached page does not prove origin health.
Working SSH access does not prove your website is reachable through Cloudflare. Cloudflare error 521 usually means the origin web server refused Cloudflare's connection. Verify the origin IP, Nginx HTTPS listener, and firewall permissions, then test Full (strict) connectivity both directly to the origin with the hostname preserved and separately through Cloudflare.
Table of Contents
- Why Does Cloudflare Return 521 When the Site Seems Available?
- First Verify Which Origin Cloudflare Is Using
- Connect Directly to the Origin While Preserving the Hostname
- Is Nginx Actually Listening on Port 443?
- Firewall Layers That Block Cloudflare Connections
- Complete the HTTPS Path for Full (strict)
- Verify the Fix Through Cloudflare
- Check Before and After Making Changes
- Frequently Asked Questions
- Sources
Why Does Cloudflare Return 521 When the Site Seems Available?
SSH works. A local HTTP request responds, yet your browser shows Cloudflare error 521. No contradiction: SSH access does not prove Nginx accepts external HTTPS connections. Local HTTP confirms only that the tested address and port respond-not that Cloudflare can reach your web service.
I separate the path into browser, Cloudflare, and origin. For orange-cloud-proxied www.example.com, your browser connects to Cloudflare; Cloudflare connects separately when it needs an origin response. That error page comes from Cloudflare, not your application. It does not prove Nginx received the request.
Cloudflare’s 521 documentation describes the origin refusing Cloudflare’s connection. Common causes are an offline web service or blocked Cloudflare requests. A firewall can reject connections while Nginx runs. The code alone does not establish the root cause. Access from your computer does not prove access from Cloudflare: rules can differ by source IP.
This hypothetical lab has one origin running distribution-packaged Nginx 1.24.0 on Ubuntu Server 24.04 LTS: no load balancer, Cloudflare Tunnel, Docker, or second reverse proxy. Cloudflare is a managed service, not a version-pinned package. SSL/TLS mode is Full (strict); expected origin HTTPS uses TCP 443, without an Origin Rules port override. TCP 80 serves only HTTP checks and HTTPS redirects.
Origin IPv4 192.0.2.10 and optional IPv6 2001:db8::10 are documentation addresses, not working internet targets; example.com is an example domain. Replace these with real values you manage before checking connectivity.
522 indicates a connection timeout; 523, an unreachable origin; 525, a failed TLS handshake; and 526, failed origin certificate validation. Different failures. Cloudflare’s Full (strict) documentation requires origin HTTPS and a trusted, unexpired certificate matching the requested hostname. A 521 does not, by itself, tell you to replace a certificate.
In troubleshooting notes, I would replace “site available” with the path that works: SSH, local HTTP, or external HTTPS. Do not count a local TCP 80 response as evidence that Cloudflare can reach origin TCP 443.
First Verify Which Origin Cloudflare Is Using
Restarting Nginx cannot fix a record pointing at the wrong server. I check the destination first. Cloudflare’s 521 documentation identifies the origin refusing Cloudflare’s connection as the underlying problem. Before changing services or firewall settings for Cloudflare error 521, compare the DNS dashboard’s address with your server’s.
This hypothetical lab runs distribution-packaged Nginx 1.24.0 on Ubuntu Server 24.04 LTS. In Cloudflare’s DNS dashboard for example.com, verify that www.example.com has an orange-cloud proxied A record pointing to 192.0.2.10. Check for additional A records with stale addresses. There is one origin, no load balancer, Cloudflare Tunnel, Docker, or second reverse proxy.
Public DNS cannot verify that origin address. On Ubuntu, dnsutils provides dig. These commands query IPv4 and IPv6 separately. The domain example.com and addresses 192.0.2.10 and 2001:db8::10 are documentation values, not working internet targets. Substitute your managed domain before running commands and your real addresses for dashboard comparisons.
dig +short www.example.com A
dig +short www.example.com AAAA
For a real proxied domain, expect Cloudflare edge IPv4 addresses from the first command; any AAAA answers from the second are edge IPv6 addresses. Compare these with Cloudflare’s published official IPv4 and IPv6 ranges. Missing 192.0.2.10? That is expected. Public AAAA answers do not prove the origin uses IPv6: visitor-to-Cloudflare and Cloudflare-to-origin connections are separate.
Check origin IPv6 only when configured. A dashboard AAAA record for www.example.com should point to 2001:db8::10 in this lab, assigned to the server and reachable. Do not add an origin AAAA record just because public DNS returns IPv6. Do not ignore an existing one because you assume IPv6 is unused.
Confirm Full (strict) mode. Cloudflare’s documentation requires origin HTTPS and a verifiable certificate. Check that no Origin Rules change the destination port. Here, HTTPS uses TCP 443; TCP 80 is only for HTTP checks and HTTPS redirects. For the next connection check, use the dashboard-verified origin address and TCP 443.
Connect Directly to the Origin While Preserving the Hostname
Typing the origin IP into your browser can test the wrong site. Nginx’s HTTPS documentation explains that certificate selection precedes HTTP and uses SNI. Requesting https://192.0.2.10/ can cause a certificate-name mismatch or reach the default virtual server. Changing only Host cannot fix TLS. Keep the hostname.
This hypothetical lab runs Nginx 1.24.0 on Ubuntu Server 24.04 LTS; the command uses curl 8.5.0. Run it from an authorized test point outside the origin. Replace www.example.com and 192.0.2.10, documentation values rather than working internet targets, with your managed hostname and origin IPv4 address. This bypasses the orange-cloud record’s Cloudflare addresses, reaching origin TCP 443 directly.
curl --noproxy '*' \
--resolve www.example.com:443:192.0.2.10 \
--connect-timeout 5 \
--max-time 15 \
--verbose \
--dump-header - \
--output /dev/null \
https://www.example.com/
--resolve overrides the destination for that hostname and port, preserving the URL hostname for SNI, certificate verification, and HTTP Host. --noproxy '*' bypasses configured forward proxies. Connection establishment gets five seconds; the entire operation gets fifteen. Connection details and response headers appear; the body is discarded. Redirects are not followed. Here is how I would interpret possible output-not observed measurements:
curl: (7)withConnection refused: TCP was refused. Check for a missing listener or active firewall rejection; the error number alone cannot identify the cause.curl: (28): Timeout. Check verbose output for connection establishment to distinguish possible packet drops from a delayed response after connecting.curl: (60): Certificate verification failed. Check hostname matching, validity dates, and trust chain. This is not TCP refusal.HTTP/1.1 200 OKor301: TLS completed; HTTP responded. A redirect does not prove destination-page or whole-application health.
Cloudflare’s Full (strict) documentation requires a valid, trusted origin certificate matching the requested hostname; do not hide verification failures with -k. Its Cloudflare error 521 documentation emphasizes refused connections. If your firewall permits only Cloudflare’s official IP ranges, temporarily authorize the test point’s outbound IP for TCP 443 with a narrowly scoped rule. Success proves that point’s access, not Cloudflare’s. Remove the temporary permission afterward.
Tip
For the hypothetical lab, curl –resolve www.example.com:443:192.0.2.10 https://www.example.com/ directs the connection to the origin IP while preserving SNI and Host information. example.com and 192.0.2.10 are documentation values, not working test targets; replace them with the real values you manage before running the command. If the origin accepts only Cloudflare addresses, your test location also needs narrowly scoped access.
Is Nginx Actually Listening on Port 443?
A green service status is not enough. Nginx listening only on TCP 80 can pass HTTP checks while the expected TCP 443 remains closed. Cloudflare’s 521 documentation lists an offline origin or refused connections as causes; its Full (strict) documentation requires origin HTTPS.
For this hypothetical Ubuntu Server 24.04 LTS lab with distribution-packaged Nginx 1.24.0, I would inspect the origin without changing its configuration or service state:
sudo systemctl status nginx --no-pager -l
sudo ss -ltnp '( sport = :80 or sport = :443 )'
sudo nginx -t
ls -l /etc/nginx/sites-enabled/example.com
readlink -e /etc/nginx/sites-enabled/example.com
sudo nginx -T
sudo journalctl -u nginx -n 50 --no-pager
sudo tail -n 50 /var/log/nginx/error.log
active (running) confirms only a running process. Check ss for LISTEN on 443 with nginx in the process field. 0.0.0.0:443 covers all local IPv4 addresses; [::]:443 covers IPv6. Do not assume IPv6 accepts IPv4 connections. Listening only on 127.0.0.1:443 prevents external access; another process occupying the port can cause Address already in use in the logs.
The enabling symlink should resolve to /etc/nginx/sites-available/example.com. No output from readlink -e? Inspect the link and target. nginx -T tests and dumps on-disk configuration, including included files-not necessarily what the running process loaded. Confirm your site file appears. For the symlink layout, see How to Install and Configure Nginx on Ubuntu.
Following Nginx’s HTTPS documentation, check the relevant server block for listen 443 ssl; and, with optional IPv6, listen [::]:443 ssl;. That block should contain server_name example.com www.example.com;, ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;, and ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;. Adapt the lab domain and associated paths before use; documentation values are not working internet targets.
Expect syntax is ok and test is successful from nginx -t. Otherwise, investigate the reported file and line, certificate access, and error log. During Cloudflare error 521, a connection that never reaches HTTP may leave no entry in /var/log/nginx/access.log. Silence proves nothing.
After fixing errors, reload the validated configuration on a running service; do not restart blindly:
sudo nginx -t && sudo systemctl reload nginx
If stopped, test and start instead:
sudo nginx -t && sudo systemctl start nginx
Recheck service status and logs afterward. I would also confirm that ss shows 443 listening on the expected address family before moving on.
Example
Hypothetical lab note: on Ubuntu Server 24.04 LTS with Nginx 1.24.0, suppose curl http://127.0.0.1/ returns HTTP 200, but ss -ltnp shows only a TCP 80 listener. Local HTTP works, yet the TCP 443 listener expected for Full (strict) is missing. This is an illustrative example, not a reported incident or measurement, showing why these checks must remain separate.
Firewall Layers That Block Cloudflare Connections
Your connection succeeding does not mean Cloudflare’s will. Different paths. Cloudflare’s 521 documentation names origin connection refusals and blocked Cloudflare addresses as possible causes. In this hypothetical Ubuntu Server 24.04 LTS lab, Full (strict) requires the TCP 443 path, following Cloudflare’s origin HTTPS requirements. Open TCP 80 is insufficient.
I check nftables, the provider firewall, and automatic blocking tools together. Provider-blocked traffic may never reach the server. For Fail2ban, inspect active jails’ ban lists; Nginx settings cannot reveal those blocks. Permission at one layer cannot override another’s denial.
sudo nft -a list ruleset
sudo timeout 20s tcpdump -i any -nn -c 50 'tcp port 443'
The first command lists active rules and handle identifiers. Runtime changes may differ from /etc/nftables.conf. Inspect hook input chains, priorities, default policies, address sets, and reject/drop rules. Rising counters during requests narrow down matches; missing counters do not mean inactive rules.
The second requires the tcpdump package; it stops after 50 packets or 20 seconds. Expiry can produce timeout exit code 124. During capture, request proxied www.example.com from another terminal; replace this documentation domain with your managed domain before use. Other HTTPS traffic may appear: compare source addresses against Cloudflare’s ranges. Output stays in the terminal, not a capture file.
An incoming SYN followed by a server RST fits active refusal: reject with tcp reset or no listening service can cause this. Repeated unanswered SYN packets suggest silent dropping, potentially causing timeouts rather than Cloudflare error 521. No packets alone cannot prove provider blocking.
Use Cloudflare’s official IPv4 and IPv6 address ranges for permissions, not a static, incomplete copy. CIDR notation matches networks rather than individual addresses. Assess TCP 443 and TCP 80, used here for HTTP checks and HTTPS redirects.
Evaluate allow rules against existing chain order and default policies; another base chain can drop an already accepted packet. Do not disable the firewall. Before changes, preserve SSH access and confirm you can restore previous rules through the provider console.
Caution
Disabling the firewall entirely can expose other services to the internet during diagnosis. Examine nftables chain order alongside provider rules; active connection refusal and silent packet drops may produce different symptoms. Before changing anything, preserve SSH access, console access, and a rollback path.
Complete the HTTPS Path for Full (strict)
TCP 80 responding does not prove HTTPS works. Cloudflare’s 521 documentation requires origin TCP 443 access for Full (strict). No listener can mean connection refusal. I separate the layers: TLS handshakes and certificate validation follow TCP connection establishment.
In this hypothetical Ubuntu Server 24.04 LTS and Nginx 1.24.0 lab, put this minimal configuration in /etc/nginx/sites-available/example.com. Nginx’s HTTPS documentation pairs the listener with the certificate chain and private key. This fixed response is diagnostic; preserve your application’s location blocks and TCP 80 HTTPS redirect.
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
return 200 "HTTPS endpoint ready\n";
}
}
Confirm /etc/nginx/sites-enabled/example.com links to this file. If optional address 2001:db8::10 is assigned to the server and used by the proxied record, add listen [::]:443 ssl; inside the block. Validate before reloading:
sudo nginx -t && sudo systemctl reload nginx
Expect syntax is ok and test is successful, not proof of external reachability. Fix unreadable-certificate or key-mismatch errors; never make the private key world-readable.
These OpenSSL 3.0.x commands connect directly, sending www.example.com through SNI. Domains and addresses are documentation values, not working internet targets. Substitute real values you manage before running them.
openssl s_client -connect 192.0.2.10:443 \
-servername www.example.com \
-verify_hostname www.example.com \
-verify_return_error -CApath /etc/ssl/certs \
-showcerts </dev/null
openssl s_client -connect 192.0.2.10:443 \
-servername www.example.com -showcerts </dev/null |
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
The first checks chain, hostname and validity against the local trust store; success should report Verify return code: 0 (ok). -showcerts lists certificates the server sends. The second displays leaf-certificate details without independent validation. Check subjectAltName for both example.com and www.example.com, and notBefore/notAfter for validity dates.
Cloudflare’s Full (strict) documentation requires a currently valid, hostname-matching certificate from a publicly trusted authority or Cloudflare Origin CA. This Let’s Encrypt chain can validate against the local CA store; Origin CA is not trusted there by default.
Cloudflare error 521 is not 525 (TLS handshake failure) or 526 (certificate validation failure). Keep Full (strict): fix the 443 listener and served certificate chain rather than switching to Flexible or disabling verification.
Caution
Switching to Flexible does not repair origin HTTPS; it changes the connection between Cloudflare and the origin to HTTP. Treat a missing TCP 443 listener separately from TLS handshake or certificate validation failures. For Full (strict), verify that the certificate covers the requested hostname, is valid, and comes from a certificate authority Cloudflare accepts.
Verify the Fix Through Cloudflare
I would not trust a loading page alone. Cache can mislead. Cloudflare’s 521 documentation describes the origin refusing Cloudflare’s connection; compare direct and proxied requests, since cached success can hide that failure.
Keep this hypothetical Ubuntu Server 24.04 LTS lab orange-cloud proxied, using Full (strict) and origin TCP 443. Cloudflare’s Full (strict) documentation requires origin certificate validation; retain verification when testing directly-no -k. Replace documentation-only www.example.com and 192.0.2.10 with values you manage before running commands.
Create a temporary Cloudflare Cache Rule bypassing cache for hostname www.example.com, path /, and query strings containing cf521check=. Check conflicting rules: a query parameter alone cannot guarantee bypass because cache keys may ignore it. Test directly from a firewall-permitted location, without opening access to everyone.
date -u +'%Y-%m-%dT%H:%M:%SZ'
token=$(date -u +%Y%m%dT%H%M%SZ)
curl -sS --connect-timeout 5 --max-time 20 \
--resolve www.example.com:443:192.0.2.10 \
-D - -o /dev/null \
"https://www.example.com/?cf521check=${token}-origin"
curl -sS --connect-timeout 5 --max-time 20 \
-D - -o /dev/null \
"https://www.example.com/?cf521check=${token}-cloudflare"
curl -sS --connect-timeout 5 --max-time 20 \
-D - -o /dev/null https://www.example.com/
The first GET connects directly, preserving the hostname and TLS SNI. The second checks the intended bypass through Cloudflare; the third requests the normal URL. -D - displays headers; -o /dev/null discards the body. A healthy homepage might return 200; check redirect destinations separately.
CF-Cache-Status: HIT cannot prove origin health. Match the check response’s BYPASS or DYNAMIC with the corresponding timestamped -cloudflare request in /var/log/nginx/access.log. A missing header proves nothing. I would require both confirmed cache bypass and arrival at the origin.
Keep monitoring separate: external HTTPS checks verify expected status and content through Cloudflare; systemctl is-active nginx checks the origin service. Its active output does not prove external reachability. Give these signals separate alerts in Prometheus and Grafana.
If Cloudflare error 521 persists, send support the UTC timestamp, error code, CF-Ray if available, destination TCP 443, and relevant sanitized access.log/error.log excerpts. After removing the temporary rule, recheck the actual origin IP and port used by the normal URL following your changes.
Check Before and After Making Changes
- Compare the proxy status, A target, and any enabled AAAA target in the Cloudflare dashboard against the actual origin configuration.
- Verify that SSL/TLS mode is Full (strict) and that no Origin Rules override the destination port.
- Connect to the origin from an authorized external location using curl –resolve to preserve the hostname, and record connection, TLS, and HTTP results separately.
- Inspect systemctl status nginx, ss -ltnp, nginx -t, and journalctl -u nginx to check service status and the TCP 443 listener.
- Check Cloudflare's official address ranges, rule order, and management recovery access in both server and provider firewalls.
- Verify the enabled virtual host symlink, certificate hostnames, chain, and validity period; apply changes to a running Nginx service with a reload only after a successful configuration test.
- Test a response through Cloudflare that is confirmed not to be cached; if the error persists, open a support ticket with the UTC timestamp, any Ray ID, destination port, and sanitized logs.
If 521 persists, include the UTC timestamp, any Ray ID, destination port, and sanitized test output in your support ticket. After the last change, recheck the origin HTTPS path Cloudflare actually uses-not just whether the homepage loads.
Frequently Asked Questions
What does Cloudflare error 521 mean?
Cloudflare error 521 is associated with a refused connection when Cloudflare attempts to contact the origin web server. A stopped Nginx service, a missing listener on the expected port, or firewall rules blocking Cloudflare addresses can cause it. The browser error alone does not establish the cause; check the origin address, service status, and network rules together.
Why do I get error 521 when SSH access works?
SSH and web traffic use different services and ports. SSH commonly uses TCP 22, while origin HTTPS in this scenario uses TCP 443. Working SSH access does not prove that the HTTPS listener or Cloudflare access rules are correct. A local HTTP response is not enough either; test external HTTPS access separately.
How does Cloudflare 521 differ from 522, 523, 525, and 526?
Error 521 generally points to connection refusal, while 522 indicates an origin connection timeout. Error 523 means the origin is unreachable, and 525 indicates a failed TLS handshake with the origin. Error 526 means the origin certificate could not be validated in Full (strict) mode. These distinctions guide troubleshooting; verify network behavior and relevant logs before deciding on the cause.
How can I test the origin without disabling Cloudflare?
From an authorized external test location, use curl –resolve to direct the hostname's TCP 443 connection to the origin IP. Keeping the hostname in the HTTPS URL preserves SNI and Host information. If the origin permits only Cloudflare addresses, grant your test IP limited access. A successful response proves access from that location, not necessarily from Cloudflare.
Which IP addresses should I allow for Cloudflare error 521?
Use the current IPv4 and IPv6 ranges published in Cloudflare's official IP list. Allowing just one observed Cloudflare address is not enough. Scope permissions to the required origin HTTPS port and your existing security policy, and inspect the provider firewall as well as nftables. Preserve management access and a rollback path when updating the lists.
Does switching SSL mode to Flexible fix error 521?
Flexible changes the Cloudflare-to-origin connection to HTTP; it does not repair a missing HTTPS listener or broken TLS configuration. Even if the symptom changes, encryption on the origin connection is removed, and redirect loops can occur. If you use Full (strict), repair the HTTPS path by checking TCP 443 access first, then the certificate hostname, trust chain, and validity period.
Sources
- Cloudflare – Error 521: Web server is down — developers.cloudflare.com
- Cloudflare – Official IPv4 and IPv6 Address Ranges — cloudflare.com
- Cloudflare – Full (strict) Origin HTTPS Requirements — developers.cloudflare.com
- Nginx – Configuring HTTPS Servers — nginx.org