{"id":1163,"date":"2026-11-05T15:22:48","date_gmt":"2026-11-05T15:22:48","guid":{"rendered":"https:\/\/www.vps.tc\/blog\/?p=1163"},"modified":"2026-11-05T09:29:45","modified_gmt":"2026-11-05T09:29:45","slug":"cloudflare-error-521-fix","status":"publish","type":"post","link":"https:\/\/www.vps.tc\/blog\/en\/cloudflare-error-521-fix\/","title":{"rendered":"How to Fix Cloudflare Error 521: Web Server Is Down"},"content":{"rendered":"<div class=\"aiw-summary\" id=\"aiw-ozet\">\n<p class=\"aiw-summary-title\">Quick Summary &#8211; Cloudflare Error 521<\/p>\n<p>Cloudflare error 521 is associated with the origin web server refusing Cloudflare&#039;s connection. A stopped service or blocked Cloudflare addresses are common causes; the error code alone does not identify which one occurred.<\/p>\n<ul>\n<li><strong>Origin address<\/strong> \u2014 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.<\/li>\n<li><strong>HTTPS listener<\/strong> \u2014 In this Full (strict) scenario with no port override, check that Nginx listens on TCP 443 on an address that accepts external connections.<\/li>\n<li><strong>Direct connection<\/strong> \u2014 Use curl &#8211;resolve from an authorized external test location to test the origin IP while preserving the hostname, SNI, and certificate verification.<\/li>\n<li><strong>Firewall rules<\/strong> \u2014 Check that server and provider rules grant the required access to Cloudflare&#039;s current IPv4 and IPv6 ranges.<\/li>\n<li><strong>TLS distinctions<\/strong> \u2014 While 521 is associated with connection refusal, 525 indicates a TLS handshake failure and 526 indicates a certificate validation failure in Full (strict) mode.<\/li>\n<li><strong>Final verification<\/strong> \u2014 Test the fix through Cloudflare using a response confirmed not to come from cache; a successful cached page does not prove origin health.<\/li>\n<\/ul>\n<\/div>\n<p class=\"aiw-lead\">Working SSH access does not prove your website is reachable through Cloudflare. Cloudflare error 521 usually means the origin web server refused Cloudflare&#039;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.<\/p>\n<div class=\"aiw-toc\" style=\"border:1px solid #dbe3ea;border-radius:8px;padding:16px 20px;margin:0 0 28px\">\n<p class=\"aiw-toc-head\"><strong>Table of Contents<\/strong><span class=\"aiw-toc-meta\"> \u00b7 16 min read<\/span><\/p>\n<ol style=\"margin:10px 0 0;padding-left:22px\">\n<li><a href=\"#why-does-cloudflare-return-521-when-the-site-seems-available\">Why Does Cloudflare Return 521 When the Site Seems Available?<\/a><\/li>\n<li><a href=\"#first-verify-which-origin-cloudflare-is-using\">First Verify Which Origin Cloudflare Is Using<\/a><\/li>\n<li><a href=\"#connect-directly-to-the-origin-while-preserving-the-hostname\">Connect Directly to the Origin While Preserving the Hostname<\/a><\/li>\n<li><a href=\"#is-nginx-actually-listening-on-port-443\">Is Nginx Actually Listening on Port 443?<\/a><\/li>\n<li><a href=\"#firewall-layers-that-block-cloudflare-connections\">Firewall Layers That Block Cloudflare Connections<\/a><\/li>\n<li><a href=\"#complete-the-https-path-for-full-strict\">Complete the HTTPS Path for Full (strict)<\/a><\/li>\n<li><a href=\"#verify-the-fix-through-cloudflare\">Verify the Fix Through Cloudflare<\/a><\/li>\n<li><a href=\"#check-before-and-after-making-changes\">Check Before and After Making Changes<\/a><\/li>\n<li><a href=\"#frequently-asked-questions\">Frequently Asked Questions<\/a><\/li>\n<li><a href=\"#sources\">Sources<\/a><\/li>\n<\/ol>\n<\/div>\n<h2 id=\"why-does-cloudflare-return-521-when-the-site-seems-available\">Why Does Cloudflare Return 521 When the Site Seems Available?<\/h2>\n<p>SSH works. A local HTTP request responds, yet your browser shows <strong>Cloudflare error 521<\/strong>. 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.<\/p>\n<p>I separate the path into browser, Cloudflare, and origin. For orange-cloud-proxied <code>www.example.com<\/code>, 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.<\/p>\n<p>Cloudflare&#8217;s 521 documentation describes the origin refusing Cloudflare&#8217;s connection. Common causes are an offline web service or blocked Cloudflare requests. A firewall can reject connections while Nginx runs. <strong>The code alone does not establish the root cause.<\/strong> Access from your computer does not prove access from Cloudflare: rules can differ by source IP.<\/p>\n<p>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.<\/p>\n<p>Origin IPv4 <code>192.0.2.10<\/code> and optional IPv6 <code>2001:db8::10<\/code> are documentation addresses, not working internet targets; <code>example.com<\/code> is an example domain. Replace these with real values you manage before checking connectivity.<\/p>\n<p><strong>522<\/strong> indicates a connection timeout; <strong>523<\/strong>, an unreachable origin; <strong>525<\/strong>, a failed TLS handshake; and <strong>526<\/strong>, failed origin certificate validation. Different failures. Cloudflare&#8217;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.<\/p>\n<p>In troubleshooting notes, I would replace &#8220;site available&#8221; 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.<\/p>\n<h2 id=\"first-verify-which-origin-cloudflare-is-using\">First Verify Which Origin Cloudflare Is Using<\/h2>\n<p>Restarting Nginx cannot fix a record pointing at the wrong server. I check the destination first. Cloudflare&#8217;s 521 documentation identifies the origin refusing Cloudflare&#8217;s connection as the underlying problem. Before changing services or firewall settings for Cloudflare error 521, compare the DNS dashboard&#8217;s address with your server&#8217;s.<\/p>\n<p>This hypothetical lab runs distribution-packaged Nginx 1.24.0 on Ubuntu Server 24.04 LTS. In Cloudflare&#8217;s DNS dashboard for <code>example.com<\/code>, verify that <code>www.example.com<\/code> has an orange-cloud proxied A record pointing to <code>192.0.2.10<\/code>. Check for additional A records with stale addresses. There is one origin, no load balancer, Cloudflare Tunnel, Docker, or second reverse proxy.<\/p>\n<p>Public DNS cannot verify that origin address. On Ubuntu, <code>dnsutils<\/code> provides <code>dig<\/code>. These commands query IPv4 and IPv6 separately. The domain <code>example.com<\/code> and addresses <code>192.0.2.10<\/code> and <code>2001:db8::10<\/code> are documentation values, not working internet targets. Substitute your managed domain before running commands and your real addresses for dashboard comparisons.<\/p>\n<pre><code>dig +short www.example.com A\ndig +short www.example.com AAAA<\/code><\/pre>\n<p>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&#8217;s published official IPv4 and IPv6 ranges. Missing <code>192.0.2.10<\/code>? That is expected. Public AAAA answers do not prove the origin uses IPv6: visitor-to-Cloudflare and Cloudflare-to-origin connections are separate.<\/p>\n<p>Check origin IPv6 only when configured. A dashboard AAAA record for <code>www.example.com<\/code> should point to <code>2001:db8::10<\/code> 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.<\/p>\n<p>Confirm <strong>Full (strict)<\/strong> mode. Cloudflare&#8217;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.<\/p>\n<h2 id=\"connect-directly-to-the-origin-while-preserving-the-hostname\">Connect Directly to the Origin While Preserving the Hostname<\/h2>\n<p>Typing the origin IP into your browser can test the wrong site. Nginx&#8217;s HTTPS documentation explains that certificate selection precedes HTTP and uses SNI. Requesting <code>https:\/\/192.0.2.10\/<\/code> can cause a certificate-name mismatch or reach the default virtual server. Changing only <code>Host<\/code> cannot fix TLS. Keep the hostname.<\/p>\n<p>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 <code>www.example.com<\/code> and <code>192.0.2.10<\/code>, documentation values rather than working internet targets, with your managed hostname and origin IPv4 address. This bypasses the orange-cloud record&#8217;s Cloudflare addresses, reaching origin TCP 443 directly.<\/p>\n<pre><code>curl --noproxy '*' \\\n  --resolve www.example.com:443:192.0.2.10 \\\n  --connect-timeout 5 \\\n  --max-time 15 \\\n  --verbose \\\n  --dump-header - \\\n  --output \/dev\/null \\\n  https:\/\/www.example.com\/<\/code><\/pre>\n<p><code>--resolve<\/code> overrides the destination for that hostname and port, preserving the URL hostname for SNI, certificate verification, and HTTP <code>Host<\/code>. <code>--noproxy '*'<\/code> 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:<\/p>\n<ul>\n<li><code>curl: (7)<\/code> with <code>Connection refused<\/code>: TCP was refused. Check for a missing listener or active firewall rejection; the error number alone cannot identify the cause.<\/li>\n<li><code>curl: (28)<\/code>: Timeout. Check verbose output for connection establishment to distinguish possible packet drops from a delayed response after connecting.<\/li>\n<li><code>curl: (60)<\/code>: Certificate verification failed. Check hostname matching, validity dates, and trust chain. This is not TCP refusal.<\/li>\n<li><code>HTTP\/1.1 200 OK<\/code> or <code>301<\/code>: TLS completed; HTTP responded. A redirect does not prove destination-page or whole-application health.<\/li>\n<\/ul>\n<p>Cloudflare&#8217;s Full (strict) documentation requires a valid, trusted origin certificate matching the requested hostname; do not hide verification failures with <code>-k<\/code>. Its Cloudflare error 521 documentation emphasizes refused connections. If your firewall permits only Cloudflare&#8217;s official IP ranges, temporarily authorize the test point&#8217;s outbound IP for TCP 443 with a narrowly scoped rule. Success proves that point&#8217;s access, not Cloudflare&#8217;s. Remove the temporary permission afterward.<\/p>\n<div class=\"aiw-callout aiw-callout-tip\">\n<p class=\"aiw-callout-label\">Tip<\/p>\n<p>For the hypothetical lab, curl &#8211;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.<\/p>\n<\/div>\n<h2 id=\"is-nginx-actually-listening-on-port-443\">Is Nginx Actually Listening on Port 443?<\/h2>\n<p>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&#8217;s 521 documentation lists an offline origin or refused connections as causes; its Full (strict) documentation requires origin HTTPS.<\/p>\n<p>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:<\/p>\n<pre><code>sudo systemctl status nginx --no-pager -l\nsudo ss -ltnp '( sport = :80 or sport = :443 )'\nsudo nginx -t\nls -l \/etc\/nginx\/sites-enabled\/example.com\nreadlink -e \/etc\/nginx\/sites-enabled\/example.com\nsudo nginx -T\nsudo journalctl -u nginx -n 50 --no-pager\nsudo tail -n 50 \/var\/log\/nginx\/error.log<\/code><\/pre>\n<p><code>active (running)<\/code> confirms only a running process. Check <code>ss<\/code> for <code>LISTEN<\/code> on 443 with <code>nginx<\/code> in the process field. <code>0.0.0.0:443<\/code> covers all local IPv4 addresses; <code>[::]:443<\/code> covers IPv6. Do not assume IPv6 accepts IPv4 connections. Listening only on <code>127.0.0.1:443<\/code> prevents external access; another process occupying the port can cause <code>Address already in use<\/code> in the logs.<\/p>\n<p>The enabling symlink should resolve to <code>\/etc\/nginx\/sites-available\/example.com<\/code>. No output from <code>readlink -e<\/code>? Inspect the link and target. <code>nginx -T<\/code> 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 <a href=\"https:\/\/www.vps.tc\/blog\/en\/install-configure-nginx-on-ubuntu\/\">How to Install and Configure Nginx on Ubuntu<\/a>.<\/p>\n<p>Following Nginx&#8217;s HTTPS documentation, check the relevant <code>server<\/code> block for <code>listen 443 ssl;<\/code> and, with optional IPv6, <code>listen [::]:443 ssl;<\/code>. That block should contain <code>server_name example.com www.example.com;<\/code>, <code>ssl_certificate \/etc\/letsencrypt\/live\/example.com\/fullchain.pem;<\/code>, and <code>ssl_certificate_key \/etc\/letsencrypt\/live\/example.com\/privkey.pem;<\/code>. Adapt the lab domain and associated paths before use; documentation values are not working internet targets.<\/p>\n<p>Expect <code>syntax is ok<\/code> and <code>test is successful<\/code> from <code>nginx -t<\/code>. 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 <code>\/var\/log\/nginx\/access.log<\/code>. Silence proves nothing.<\/p>\n<p>After fixing errors, reload the validated configuration on a running service; do not restart blindly:<\/p>\n<pre><code>sudo nginx -t &amp;&amp; sudo systemctl reload nginx<\/code><\/pre>\n<p>If stopped, test and start instead:<\/p>\n<pre><code>sudo nginx -t &amp;&amp; sudo systemctl start nginx<\/code><\/pre>\n<p>Recheck service status and logs afterward. I would also confirm that <code>ss<\/code> shows 443 listening on the expected address family before moving on.<\/p>\n<div class=\"aiw-callout aiw-callout-example\">\n<p class=\"aiw-callout-label\">Example<\/p>\n<p>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.<\/p>\n<\/div>\n<h2 id=\"firewall-layers-that-block-cloudflare-connections\">Firewall Layers That Block Cloudflare Connections<\/h2>\n<p>Your connection succeeding does not mean Cloudflare&#8217;s will. Different paths. Cloudflare&#8217;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&#8217;s origin HTTPS requirements. Open TCP 80 is insufficient.<\/p>\n<p>I check nftables, the provider firewall, and automatic blocking tools together. Provider-blocked traffic may never reach the server. For Fail2ban, inspect active jails&#8217; ban lists; Nginx settings cannot reveal those blocks. Permission at one layer cannot override another&#8217;s denial.<\/p>\n<pre><code>sudo nft -a list ruleset\nsudo timeout 20s tcpdump -i any -nn -c 50 'tcp port 443'<\/code><\/pre>\n<p>The first command lists active rules and <code>handle<\/code> identifiers. Runtime changes may differ from <code>\/etc\/nftables.conf<\/code>. Inspect <code>hook input<\/code> chains, priorities, default policies, address sets, and <code>reject<\/code>\/<code>drop<\/code> rules. Rising counters during requests narrow down matches; missing counters do not mean inactive rules.<\/p>\n<p>The second requires the <code>tcpdump<\/code> package; it stops after 50 packets or 20 seconds. Expiry can produce <code>timeout<\/code> exit code 124. During capture, request proxied <code>www.example.com<\/code> from another terminal; replace this documentation domain with your managed domain before use. Other HTTPS traffic may appear: compare source addresses against Cloudflare&#8217;s ranges. Output stays in the terminal, not a capture file.<\/p>\n<p>An incoming SYN followed by a server RST fits active refusal: <code>reject with tcp reset<\/code> 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.<\/p>\n<p>Use Cloudflare&#8217;s official IPv4 and IPv6 address ranges for permissions, not a static, incomplete copy. <a href=\"https:\/\/www.vps.tc\/blog\/en\/what-is-cidr-ip-range-calculation\/\">CIDR notation<\/a> matches networks rather than individual addresses. Assess TCP 443 and TCP 80, used here for HTTP checks and HTTPS redirects.<\/p>\n<p>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.<\/p>\n<div class=\"aiw-callout aiw-callout-warn\">\n<p class=\"aiw-callout-label\">Caution<\/p>\n<p>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.<\/p>\n<\/div>\n<h2 id=\"complete-the-https-path-for-full-strict\">Complete the HTTPS Path for Full (strict)<\/h2>\n<p>TCP 80 responding does not prove HTTPS works. Cloudflare&#8217;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.<\/p>\n<p>In this hypothetical Ubuntu Server 24.04 LTS and Nginx 1.24.0 lab, put this minimal configuration in <code>\/etc\/nginx\/sites-available\/example.com<\/code>. Nginx&#8217;s HTTPS documentation pairs the listener with the certificate chain and private key. This fixed response is diagnostic; preserve your application&#8217;s <code>location<\/code> blocks and TCP 80 HTTPS redirect.<\/p>\n<pre><code>server {\n    listen 443 ssl;\n    server_name example.com www.example.com;\n\n    ssl_certificate \/etc\/letsencrypt\/live\/example.com\/fullchain.pem;\n    ssl_certificate_key \/etc\/letsencrypt\/live\/example.com\/privkey.pem;\n\n    access_log \/var\/log\/nginx\/access.log;\n    error_log \/var\/log\/nginx\/error.log;\n\n    location \/ {\n        return 200 \"HTTPS endpoint ready\\n\";\n    }\n}<\/code><\/pre>\n<p>Confirm <code>\/etc\/nginx\/sites-enabled\/example.com<\/code> links to this file. If optional address <code>2001:db8::10<\/code> is assigned to the server and used by the proxied record, add <code>listen [::]:443 ssl;<\/code> inside the block. Validate before reloading:<\/p>\n<pre><code>sudo nginx -t &amp;&amp; sudo systemctl reload nginx<\/code><\/pre>\n<p>Expect <code>syntax is ok<\/code> and <code>test is successful<\/code>, not proof of external reachability. Fix unreadable-certificate or key-mismatch errors; never make the private key world-readable.<\/p>\n<p>These OpenSSL 3.0.x commands connect directly, sending <code>www.example.com<\/code> through SNI. Domains and addresses are documentation values, not working internet targets. Substitute real values you manage before running them.<\/p>\n<pre><code>openssl s_client -connect 192.0.2.10:443 \\\n  -servername www.example.com \\\n  -verify_hostname www.example.com \\\n  -verify_return_error -CApath \/etc\/ssl\/certs \\\n  -showcerts &lt;\/dev\/null\n\nopenssl s_client -connect 192.0.2.10:443 \\\n  -servername www.example.com -showcerts &lt;\/dev\/null |\n  openssl x509 -noout -subject -issuer -dates -ext subjectAltName<\/code><\/pre>\n<p>The first checks chain, hostname and validity against the local trust store; success should report <code>Verify return code: 0 (ok)<\/code>. <code>-showcerts<\/code> lists certificates the server sends. The second displays leaf-certificate details without independent validation. Check <code>subjectAltName<\/code> for both <code>example.com<\/code> and <code>www.example.com<\/code>, and <code>notBefore<\/code>\/<code>notAfter<\/code> for validity dates.<\/p>\n<p>Cloudflare&#8217;s Full (strict) documentation requires a currently valid, hostname-matching certificate from a publicly trusted authority or Cloudflare Origin CA. This Let&#8217;s Encrypt chain can validate against the local CA store; Origin CA is not trusted there by default.<\/p>\n<p>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.<\/p>\n<div class=\"aiw-callout aiw-callout-warn\">\n<p class=\"aiw-callout-label\">Caution<\/p>\n<p>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.<\/p>\n<\/div>\n<h2 id=\"verify-the-fix-through-cloudflare\">Verify the Fix Through Cloudflare<\/h2>\n<p>I would not trust a loading page alone. Cache can mislead. Cloudflare&#8217;s 521 documentation describes the origin refusing Cloudflare&#8217;s connection; compare direct and proxied requests, since cached success can hide that failure.<\/p>\n<p>Keep this hypothetical Ubuntu Server 24.04 LTS lab orange-cloud proxied, using <code>Full (strict)<\/code> and origin TCP 443. Cloudflare&#8217;s Full (strict) documentation requires origin certificate validation; retain verification when testing directly-no <code>-k<\/code>. Replace documentation-only <code>www.example.com<\/code> and <code>192.0.2.10<\/code> with values you manage before running commands.<\/p>\n<p>Create a temporary Cloudflare Cache Rule bypassing cache for hostname <code>www.example.com<\/code>, path <code>\/<\/code>, and query strings containing <code>cf521check=<\/code>. 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.<\/p>\n<pre><code>date -u +'%Y-%m-%dT%H:%M:%SZ'\ntoken=$(date -u +%Y%m%dT%H%M%SZ)\n\ncurl -sS --connect-timeout 5 --max-time 20 \\\n  --resolve www.example.com:443:192.0.2.10 \\\n  -D - -o \/dev\/null \\\n  \"https:\/\/www.example.com\/?cf521check=${token}-origin\"\n\ncurl -sS --connect-timeout 5 --max-time 20 \\\n  -D - -o \/dev\/null \\\n  \"https:\/\/www.example.com\/?cf521check=${token}-cloudflare\"\n\ncurl -sS --connect-timeout 5 --max-time 20 \\\n  -D - -o \/dev\/null https:\/\/www.example.com\/<\/code><\/pre>\n<p>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. <code>-D -<\/code> displays headers; <code>-o \/dev\/null<\/code> discards the body. A healthy homepage might return <code>200<\/code>; check redirect destinations separately.<\/p>\n<p><code>CF-Cache-Status: HIT<\/code> cannot prove origin health. Match the check response&#8217;s <code>BYPASS<\/code> or <code>DYNAMIC<\/code> with the corresponding timestamped <code>-cloudflare<\/code> request in <code>\/var\/log\/nginx\/access.log<\/code>. A missing header proves nothing. I would require both confirmed cache bypass and arrival at the origin.<\/p>\n<p>Keep monitoring separate: external HTTPS checks verify expected status and content through Cloudflare; <code>systemctl is-active nginx<\/code> checks the origin service. Its <code>active<\/code> output does not prove external reachability. Give these signals separate alerts in <a href=\"https:\/\/www.vps.tc\/blog\/en\/prometheus-grafana-setup-vps-monitoring\/\">Prometheus and Grafana<\/a>.<\/p>\n<p>If Cloudflare error 521 persists, send support the UTC timestamp, error code, <code>CF-Ray<\/code> if available, destination TCP 443, and relevant sanitized <code>access.log<\/code>\/<code>error.log<\/code> excerpts. After removing the temporary rule, recheck the actual origin IP and port used by the normal URL following your changes.<\/p>\n<h2 id=\"check-before-and-after-making-changes\">Check Before and After Making Changes<\/h2>\n<ul class=\"aiw-checklist\">\n<li>Compare the proxy status, A target, and any enabled AAAA target in the Cloudflare dashboard against the actual origin configuration.<\/li>\n<li>Verify that SSL\/TLS mode is Full (strict) and that no Origin Rules override the destination port.<\/li>\n<li>Connect to the origin from an authorized external location using curl &#8211;resolve to preserve the hostname, and record connection, TLS, and HTTP results separately.<\/li>\n<li>Inspect systemctl status nginx, ss -ltnp, nginx -t, and journalctl -u nginx to check service status and the TCP 443 listener.<\/li>\n<li>Check Cloudflare&#039;s official address ranges, rule order, and management recovery access in both server and provider firewalls.<\/li>\n<li>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.<\/li>\n<li>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.<\/li>\n<\/ul>\n<div class=\"aiw-cta\">\n<p>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.<\/p>\n<p class=\"aiw-cta-action\"><a href=\"https:\/\/www.vps.tc\/en\/vps\">Explore VPS plans<\/a><\/p>\n<\/div>\n<h2 id=\"frequently-asked-questions\">Frequently Asked Questions<\/h2>\n<div class=\"aiw-faq\">\n<details class=\"aiw-faq-item\" open>\n<summary>What does Cloudflare error 521 mean?<\/summary>\n<p>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.<\/p>\n<\/details>\n<details class=\"aiw-faq-item\">\n<summary>Why do I get error 521 when SSH access works?<\/summary>\n<p>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.<\/p>\n<\/details>\n<details class=\"aiw-faq-item\">\n<summary>How does Cloudflare 521 differ from 522, 523, 525, and 526?<\/summary>\n<p>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.<\/p>\n<\/details>\n<details class=\"aiw-faq-item\">\n<summary>How can I test the origin without disabling Cloudflare?<\/summary>\n<p>From an authorized external test location, use curl &#8211;resolve to direct the hostname&#039;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.<\/p>\n<\/details>\n<details class=\"aiw-faq-item\">\n<summary>Which IP addresses should I allow for Cloudflare error 521?<\/summary>\n<p>Use the current IPv4 and IPv6 ranges published in Cloudflare&#039;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.<\/p>\n<\/details>\n<details class=\"aiw-faq-item\">\n<summary>Does switching SSL mode to Flexible fix error 521?<\/summary>\n<p>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.<\/p>\n<\/details>\n<\/div>\n<h2 id=\"sources\">Sources<\/h2>\n<ul class=\"aiw-sources\">\n<li><a href=\"https:\/\/developers.cloudflare.com\/support\/troubleshooting\/http-status-codes\/cloudflare-5xx-errors\/error-521\/\" target=\"_blank\" rel=\"noopener\">Cloudflare &#8211; Error 521: Web server is down<\/a> \u2014 developers.cloudflare.com<\/li>\n<li><a href=\"https:\/\/www.cloudflare.com\/ips\/\" target=\"_blank\" rel=\"noopener\">Cloudflare &#8211; Official IPv4 and IPv6 Address Ranges<\/a> \u2014 cloudflare.com<\/li>\n<li><a href=\"https:\/\/developers.cloudflare.com\/ssl\/origin-configuration\/ssl-modes\/full-strict\/\" target=\"_blank\" rel=\"noopener\">Cloudflare &#8211; Full (strict) Origin HTTPS Requirements<\/a> \u2014 developers.cloudflare.com<\/li>\n<li><a href=\"https:\/\/nginx.org\/en\/docs\/http\/configuring_https_servers.html\" target=\"_blank\" rel=\"noopener\">Nginx &#8211; Configuring HTTPS Servers<\/a> \u2014 nginx.org<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Working SSH access does not mean Cloudflare can reach your website. When investigating error 521, verify the origin address, the TCP 443 listener, and the firewall rules applied to Cloudflare connections separately.<\/p>\n","protected":false},"author":2,"featured_media":1161,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1163","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hosting"],"lang":"en","translations":{"en":1163,"tr":1162},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/posts\/1163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/comments?post=1163"}],"version-history":[{"count":1,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/posts\/1163\/revisions"}],"predecessor-version":[{"id":1165,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/posts\/1163\/revisions\/1165"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/media\/1161"}],"wp:attachment":[{"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/media?parent=1163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/categories?post=1163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vps.tc\/blog\/wp-json\/wp\/v2\/tags?post=1163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}