Error Medic

Cloudflare API Timeout: Fix Error 524, 522, and RequestTimeout Errors

Fix Cloudflare API timeout errors (524, 522, 408) with step-by-step diagnosis: increase origin timeouts, whitelist Cloudflare IPs, and optimize long-running req

Last updated:
Last verified:
2,248 words
Key Takeaways
  • Error 524 (A Timeout Occurred) means Cloudflare successfully connected to your origin but the origin did not return an HTTP response within Cloudflare's 100-second limit for free/pro plans.
  • Error 522 (Connection Timed Out) means Cloudflare could not establish a TCP connection to your origin server within 15 seconds—commonly caused by firewall rules blocking Cloudflare IP ranges.
  • Cloudflare API v4 requests themselves (to api.cloudflare.com) can return 408 or 504 status codes during platform incidents or when large Zone/DNS payloads exceed gateway limits.
  • Quick fix summary: For 524 errors optimize or offload the slow origin endpoint; for 522 errors whitelist all Cloudflare IP ranges in your origin firewall; for api.cloudflare.com 504/408 errors implement exponential backoff and check status.cloudflare.com.
Fix Approaches Compared
MethodWhen to UseTime to ImplementRisk
Increase proxy_read_timeout (Nginx) / ProxyTimeout (Apache)Origin response exceeds 100s on Business/Enterprise or custom timeout plans5 minLow — only affects upstream wait
Whitelist Cloudflare IP ranges in firewall/security groupError 522 — TCP connection drops before handshake10 minLow — Cloudflare IPs are published and static per update cycle
Move long-running work to async queue + webhookEndpoint legitimately takes >100s (data exports, report generation)2–8 hoursMedium — requires application refactor
Use Cloudflare Workers + waitUntil() for background processingRequest must stay under 30s wall time but work can continue async1–3 hoursLow — Workers are isolated from origin
Enable Cloudflare Argo / Smart RoutingPersistent intermittent timeouts due to poor BGP path to origin15 minLow — additive feature, no config changes needed
Implement exponential backoff on api.cloudflare.com callsScripts hitting api.cloudflare.com and receiving 429/504 transiently30 minLow — defensive client-side change only
Switch to Cloudflare Stream/R2 for large payload endpointsUploads or downloads timing out due to payload size4–16 hoursMedium — storage migration required

Understanding Cloudflare API Timeout Errors

The phrase "Cloudflare API timeout" covers two distinct failure modes that engineers conflate:

  1. Your users hit your origin through Cloudflare and receive a 5xx timeout error page served by Cloudflare.
  2. Your automation hits api.cloudflare.com (Cloudflare's own management API) and receives a timeout response.

Both require different diagnosis paths. This guide covers both.


Error Taxonomy

HTTP Status Cloudflare Code Meaning
522 CF-RAY present TCP connection to origin failed within 15s
524 CF-RAY present TCP connected, but origin never sent HTTP response within timeout window
521 CF-RAY present Origin actively refused connection (port closed)
408 No CF-RAY api.cloudflare.com request timeout (client-side or gateway)
504 No CF-RAY api.cloudflare.com gateway timeout (Cloudflare infra)

The presence of the CF-RAY response header tells you whether Cloudflare proxied the request (your origin) or the error originated from Cloudflare's API platform itself.


Step 1: Identify Which Timeout You Have

Run the following curl to capture headers:

curl -svo /dev/null https://yourdomain.com/your-slow-endpoint 2>&1 | grep -E 'CF-RAY|< HTTP|cf-cache'

If you see CF-RAY: in the output, Cloudflare proxied the request and the timeout is between Cloudflare and your origin.

For api.cloudflare.com errors, add -w "%{http_code}" to your API calls:

curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/zones"

A 504 or 408 from api.cloudflare.com warrants checking https://www.cloudflarestatus.com before any local debugging.


Step 2: Diagnose Error 524 (Origin Too Slow)

Error 524 fires when your origin holds the connection open but never completes an HTTP response. Common triggers:

  • Database queries without proper indexes on large tables
  • Synchronous file processing (PDF generation, image resizing) on the web thread
  • External HTTP calls from your origin with no timeout set
  • PHP/Python scripts that flush() no output until completion

Measure your actual origin response time bypassing Cloudflare:

# Replace 1.2.3.4 with your real origin IP
curl -o /dev/null -w "\nTime: %{time_total}s\nHTTP: %{http_code}\n" \
  --resolve yourdomain.com:443:1.2.3.4 \
  https://yourdomain.com/your-slow-endpoint

If time_total exceeds 100 seconds you will always get 524 on standard Cloudflare plans.

Nginx origin — increase upstream timeout:

location /your-slow-endpoint {
    proxy_read_timeout 300s;
    proxy_connect_timeout 10s;
    proxy_send_timeout 300s;
    proxy_pass http://upstream_backend;
}

Note: Increasing proxy_read_timeout on your origin server does not change Cloudflare's 100-second gateway limit on Free/Pro/Business plans. Enterprise plans can request a longer timeout from Cloudflare support. The correct long-term fix is making the endpoint respond faster or going async.

Check what Cloudflare's edge sees via diagnostic headers:

curl -I -H "CF-Debug: 1" https://yourdomain.com/your-slow-endpoint 2>&1 | head -30

Step 3: Diagnose Error 522 (TCP Connection Failed)

Error 522 fires when Cloudflare cannot complete a TCP handshake to your origin's IP within 15 seconds. The three most common causes:

  1. Origin firewall blocking Cloudflare IPs — the #1 cause
  2. Origin server process not listening on the expected port
  3. Network route instability between Cloudflare's edge and your origin datacenter

Verify Cloudflare IPs are whitelisted:

# Download current Cloudflare IPv4 ranges
curl -s https://www.cloudflare.com/ips-v4 -o /tmp/cf-ips-v4.txt
curl -s https://www.cloudflare.com/ips-v6 -o /tmp/cf-ips-v6.txt

# Check if iptables is blocking them (Linux)
sudo iptables -L INPUT -n --line-numbers | grep -v ACCEPT | head -30

# For AWS Security Groups — list rules for your web SG
aws ec2 describe-security-groups \
  --group-ids sg-xxxxxxxx \
  --query 'SecurityGroups[*].IpPermissions' \
  --output table

Add Cloudflare IP ranges to ufw (Ubuntu/Debian):

while IFS= read -r ip; do
  sudo ufw allow from "$ip" to any port 443
  sudo ufw allow from "$ip" to any port 80
done < /tmp/cf-ips-v4.txt

while IFS= read -r ip; do
  sudo ufw allow from "$ip" to any port 443
  sudo ufw allow from "$ip" to any port 80
done < /tmp/cf-ips-v6.txt

sudo ufw reload

Test TCP reachability from an external machine:

nc -zv YOUR_ORIGIN_IP 443
# Should print: Connection to YOUR_ORIGIN_IP 443 port [tcp/https] succeeded!

Step 4: Diagnose api.cloudflare.com Timeouts (Management API)

If your Terraform, CI/CD pipeline, or scripts are receiving timeouts when calling Cloudflare's management API:

Check Cloudflare API status:

curl -s https://www.cloudflarestatus.com/api/v2/status.json | \
  python3 -c "import sys,json; s=json.load(sys.stdin); print(s['status']['description'])"

Test API connectivity and latency:

curl -w "\nDNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/user/tokens/verify"

Check if you are hitting rate limits (Cloudflare API allows 1200 req/5min per token):

# Look for X-RateLimit-Remaining and X-RateLimit-Reset headers
curl -I -H "Authorization: Bearer $CF_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/zones" 2>&1 | \
  grep -i 'ratelimit\|x-request-id\|cf-ray'

Step 5: Implement Async Pattern for Long-Running Endpoints

If your endpoint genuinely requires more than 100 seconds (report generation, bulk data export), the correct architecture is:

  1. Client POSTs a job request → origin returns 202 Accepted with a job_id immediately
  2. Origin processes in a background worker (Celery, Sidekiq, BullMQ)
  3. Client polls GET /jobs/{job_id}/status (fast endpoint, always < 1s)
  4. When status is complete, client fetches result from GET /jobs/{job_id}/result

This pattern eliminates all Cloudflare timeout concerns because no single HTTP request takes more than a second.

Frequently Asked Questions

bash
#!/usr/bin/env bash
# cloudflare-timeout-diag.sh — Comprehensive Cloudflare timeout diagnostic script
# Usage: CF_API_TOKEN=xxx CF_ZONE_ID=xxx ORIGIN_IP=1.2.3.4 DOMAIN=example.com bash cloudflare-timeout-diag.sh

set -euo pipefail

DOMAIN="${DOMAIN:-example.com}"
ORIGIN_IP="${ORIGIN_IP:-}"
CF_API_TOKEN="${CF_API_TOKEN:-}"
CF_ZONE_ID="${CF_ZONE_ID:-}"
TEST_PATH="${TEST_PATH:-/}"

echo "========================================"
echo " Cloudflare Timeout Diagnostic"
echo "========================================"
echo ""

# 1. Check Cloudflare platform status
echo "[1/7] Cloudflare platform status..."
CF_STATUS=$(curl -s https://www.cloudflarestatus.com/api/v2/status.json)
STATUS_DESC=$(echo "$CF_STATUS" | python3 -c "import sys,json; print(json.load(sys.stdin)['status']['description'])")
echo "    Status: $STATUS_DESC"
echo ""

# 2. DNS resolution check
echo "[2/7] DNS resolution for $DOMAIN..."
RESOLVED_IP=$(dig +short "$DOMAIN" A | tail -1)
echo "    Resolved IP: $RESOLVED_IP"
if [ -n "$ORIGIN_IP" ] && [ "$RESOLVED_IP" != "$ORIGIN_IP" ]; then
  echo "    INFO: Resolved IP differs from ORIGIN_IP — traffic is proxied through Cloudflare (expected)"
fi
echo ""

# 3. Cloudflare proxy response timing (through Cloudflare edge)
echo "[3/7] Response time through Cloudflare edge..."
curl -o /dev/null -s \
  -w "    DNS Lookup:    %{time_namelookup}s\n    TCP Connect:   %{time_connect}s\n    SSL Handshake: %{time_appconnect}s\n    TTFB:          %{time_starttransfer}s\n    Total:         %{time_total}s\n    HTTP Status:   %{http_code}\n" \
  -H "Cache-Control: no-cache" \
  "https://${DOMAIN}${TEST_PATH}"
echo ""

# 4. Direct origin response timing (bypass Cloudflare)
if [ -n "$ORIGIN_IP" ]; then
  echo "[4/7] Response time directly to origin (bypassing Cloudflare)..."
  curl -o /dev/null -s \
    --resolve "${DOMAIN}:443:${ORIGIN_IP}" \
    -w "    TTFB:        %{time_starttransfer}s\n    Total:       %{time_total}s\n    HTTP Status: %{http_code}\n" \
    -H "Cache-Control: no-cache" \
    "https://${DOMAIN}${TEST_PATH}" || echo "    FAILED — origin may be blocking direct connections"
  echo ""

  # 5. TCP reachability check
  echo "[5/7] TCP port 443 reachability to origin $ORIGIN_IP..."
  if nc -zv -w 5 "$ORIGIN_IP" 443 2>&1 | grep -q succeeded; then
    echo "    TCP port 443: OPEN"
  else
    echo "    TCP port 443: BLOCKED or CLOSED — likely cause of Error 522"
    echo "    ACTION: Whitelist Cloudflare IP ranges in your firewall"
    echo "    Cloudflare IPv4: https://www.cloudflare.com/ips-v4"
    echo "    Cloudflare IPv6: https://www.cloudflare.com/ips-v6"
  fi
  echo ""
else
  echo "[4/7] Skipping direct origin test (set ORIGIN_IP to enable)"
  echo "[5/7] Skipping TCP reachability test (set ORIGIN_IP to enable)"
  echo ""
fi

# 6. Cloudflare Management API connectivity and rate limit check
if [ -n "$CF_API_TOKEN" ]; then
  echo "[6/7] Cloudflare Management API (api.cloudflare.com) health..."
  API_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" \
    -H "Authorization: Bearer $CF_API_TOKEN" \
    -H "Content-Type: application/json" \
    "https://api.cloudflare.com/client/v4/user/tokens/verify")
  HTTP_CODE=$(echo "$API_RESPONSE" | grep 'HTTP_CODE:' | cut -d: -f2)
  SUCCESS=$(echo "$API_RESPONSE" | python3 -c "import sys,json; body=sys.stdin.read().split('\nHTTP_CODE:')[0]; print(json.loads(body).get('success','?'))")
  echo "    HTTP Status: $HTTP_CODE"
  echo "    API Success: $SUCCESS"

  if [ -n "$CF_ZONE_ID" ]; then
    echo "    Checking rate limit headers for zone $CF_ZONE_ID..."
    RL_HEADERS=$(curl -sI \
      -H "Authorization: Bearer $CF_API_TOKEN" \
      "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}" 2>&1 | \
      grep -iE 'x-ratelimit|cf-ray|x-request-id')
    echo "$RL_HEADERS" | sed 's/^/    /'
  fi
else
  echo "[6/7] Skipping API health check (set CF_API_TOKEN to enable)"
fi
echo ""

# 7. Check if Cloudflare IPs are currently whitelisted in ufw (if present)
echo "[7/7] Local firewall check (ufw)..."
if command -v ufw &>/dev/null; then
  CF_IP_SAMPLE="173.245.48.0"
  if sudo ufw status | grep -q "$CF_IP_SAMPLE"; then
    echo "    ufw: Cloudflare IPs appear whitelisted (sample $CF_IP_SAMPLE found)"
  else
    echo "    ufw: Cloudflare IPs NOT found in ruleset — may cause Error 522"
    echo "    Run: curl https://www.cloudflare.com/ips-v4 | while read ip; do sudo ufw allow from \$ip to any port 443; done"
  fi
else
  echo "    ufw not installed — check iptables/nftables/cloud security groups manually"
fi

echo ""
echo "========================================"
echo " Diagnostic complete"
echo "========================================"
E

Error Medic Editorial

The Error Medic Editorial team is composed of senior DevOps engineers, SREs, and cloud architects with collective experience across AWS, GCP, Azure, and major CDN platforms including Cloudflare, Fastly, and Akamai. We specialize in translating cryptic infrastructure errors into actionable, production-tested remediation guides.

Sources

Related Articles in Cloudflare Api

Explore More API Errors Guides