What's Actually Happening

Cloudflare returns a 524 timeout error when the origin server takes too long to respond. The request exceeds Cloudflare's 100-second timeout limit.

The Error You'll See

bash
Error 524: A timeout occurred
A timeout occurred while waiting for your web server to respond.

Browser error:

html
<h1>524 timeout</h1>
<p>A timeout occurred</p>

Cloudflare dashboard:

bash
Status: 524
Error: Timeout Occurred

Curl test:

```bash $ curl -I https://example.com

HTTP/2 524 ```

Why This Happens

  1. 1.Long-running requests - Origin takes > 100 seconds to respond
  2. 2.Heavy database queries - Slow database operations
  3. 3.Large file processing - Server processing large files
  4. 4.External API calls - Waiting for slow external services
  5. 5.Server overload - Origin server under heavy load
  6. 6.Network issues - Connectivity problems between Cloudflare and origin

Step 1: Check Error Details

```bash # Check Cloudflare logs: # Cloudflare Dashboard -> Analytics & Logs -> Logs

# Note the URL path causing timeout # Note the time of occurrence

# Test direct to origin: curl -I http://origin-server-ip/path

# Test through Cloudflare: curl -I https://example.com/path

# Check response time: time curl -I https://example.com/path

# Check with verbose output: curl -v https://example.com/path 2>&1 | grep -E "timeout|time_total" ```

Step 2: Bypass Cloudflare for Testing

```bash # Test origin directly:

# Get origin IP: dig example.com +short

# Or check DNS: nslookup example.com

# Test with hosts file: # Add to /etc/hosts: # ORIGIN_IP example.com

# Test: curl -I http://origin-ip/path

# Or test with Host header: curl -H "Host: example.com" http://origin-ip/path

# Compare response times: # Direct vs through Cloudflare

# If direct is fast, issue might be Cloudflare-to-origin connectivity ```

Step 3: Optimize Long-Running Processes

```php // PHP: Process in background

// Don't wait for completion: ignore_user_abort(true); set_time_limit(0);

// Process in background: exec('php /path/to/script.php > /dev/null 2>&1 &');

// Return immediately: header('Content-Type: application/json'); echo json_encode(['status' => 'processing']); ```

```python # Python: Use async processing

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

def long_running_task(): # Heavy processing time.sleep(120)

@app.post("/process") async def process(background_tasks: BackgroundTasks): background_tasks.add_task(long_running_task) return {"status": "processing"} ```

```javascript // Node.js: Use job queue

const Queue = require('bull'); const processQueue = new Queue('processing');

app.post('/process', async (req, res) => { await processQueue.add({ data: req.body }); res.json({ status: 'queued' }); }); ```

Step 4: Increase Server Resources

```bash # Check server resources:

# CPU: top -bn1 | head -20

# Memory: free -m

# Disk I/O: iostat -x 1 5

# Network: netstat -i

# Check slow queries: # MySQL: mysql -e "SHOW FULL PROCESSLIST"

# PostgreSQL: psql -c "SELECT * FROM pg_stat_activity WHERE state = 'active'"

# Optimize database: # - Add indexes # - Optimize queries # - Increase cache

# Increase PHP limits: # php.ini: max_execution_time = 300 memory_limit = 512M ```

Step 5: Implement Polling Pattern

```javascript // Client-side polling:

async function processLargeFile(fileId) { // Start processing const response = await fetch('/api/process', { method: 'POST', body: JSON.stringify({ fileId }) });

const { taskId } = await response.json();

// Poll for status let status = 'pending'; while (status === 'pending') { await new Promise(r => setTimeout(r, 5000)); // Wait 5 seconds const statusResponse = await fetch(/api/status/${taskId}); status = (await statusResponse.json()).status; }

return status; } ```

```python # Server-side task status:

import uuid from flask import Flask, jsonify

tasks = {}

@app.route('/api/process', methods=['POST']) def start_process(): task_id = str(uuid.uuid4()) tasks[task_id] = {'status': 'pending'} # Start background task process_in_background.delay(task_id) return jsonify({'taskId': task_id})

@app.route('/api/status/<task_id>') def get_status(task_id): return jsonify(tasks.get(task_id, {})) ```

Step 6: Use Webhooks for Completion

```python # Start long process with webhook callback:

@app.route('/api/process', methods=['POST']) def process_with_webhook(): webhook_url = request.json.get('webhookUrl')

def long_task(): result = do_heavy_processing() # Call webhook when done requests.post(webhook_url, json=result)

threading.Thread(target=long_task).start() return jsonify({'status': 'processing'}) ```

```javascript // Client receives webhook:

app.post('/webhook/complete', (req, res) => { const result = req.body; // Handle completion notifyUser(result); res.sendStatus(200); }); ```

Step 7: Configure Cloudflare Timeouts

```bash # Cloudflare timeout options:

# 1. Enterprise plan: Extended timeout # Contact Cloudflare support for 600-second timeout

# 2. Use Cloudflare Workers: # Workers can run longer (30s CPU, 15min wall time)

// worker.js addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) })

async function handleRequest(request) { // Forward to origin with longer wait const response = await fetch(originUrl, { // Worker can wait longer }) return response }

# 3. Use Argo Smart Routing: # Reduces latency between Cloudflare and origin # Cloudflare Dashboard -> Traffic -> Argo

# 4. Adjust origin response timeout: # Not directly configurable on free plans ```

Step 8: Check Origin Server Logs

```bash # Check web server logs:

# Nginx: tail -f /var/log/nginx/error.log grep -i timeout /var/log/nginx/error.log

# Apache: tail -f /var/log/apache2/error.log grep -i timeout /var/log/apache2/error.log

# Check access logs for slow requests: awk '$NF > 60' /var/log/nginx/access.log # Requests > 60 seconds

# PHP-FPM: tail -f /var/log/php-fpm/error.log

# Check PHP slow log: tail -f /var/log/php-fpm/slow.log

# Application logs: tail -f /var/www/html/storage/logs/laravel.log # Laravel tail -f /var/www/html/wp-content/debug.log # WordPress ```

Step 9: Implement Caching

```nginx # Cache heavy responses:

# Nginx caching: proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;

server { location /api/heavy-endpoint { proxy_cache my_cache; proxy_cache_valid 200 10m; proxy_pass http://origin; } }

# Cache at application level:

# Redis caching: $result = $redis->get('cache_key'); if (!$result) { $result = heavy_operation(); $redis->setex('cache_key', 600, $result); } return $result; ```

```php // PHP Laravel cache:

$result = Cache::remember('heavy_data', 600, function () { return DB::select('SELECT /* heavy query */'); }); ```

Step 10: Cloudflare 524 Verification Script

```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-cf-524.sh #!/bin/bash

DOMAIN=$1 PATH=${2:-"/"}

echo "=== DNS Resolution ===" dig $DOMAIN +short

echo "" echo "=== Direct Origin Test ===" ORIGIN_IP=$(dig $DOMAIN +short | head -1) echo "Origin IP: $ORIGIN_IP" echo "Testing direct connection..." time curl -I -m 120 --resolve $DOMAIN:80:$ORIGIN_IP http://$DOMAIN$PATH 2>&1 | head -10

echo "" echo "=== Cloudflare Test ===" echo "Testing through Cloudflare..." time curl -I -m 120 https://$DOMAIN$PATH 2>&1 | head -10

echo "" echo "=== Cloudflare Status ===" curl -s https://www.cloudflarestatus.com/api/v2/summary.json | jq '.status.description'

echo "" echo "=== Check Response Codes ===" echo "Direct: $(curl -s -o /dev/null -w '%{http_code}' --resolve $DOMAIN:80:$ORIGIN_IP http://$DOMAIN$PATH)" echo "Cloudflare: $(curl -s -o /dev/null -w '%{http_code}' https://$DOMAIN$PATH)"

echo "" echo "=== Recommendations ===" echo "1. If origin slow: optimize server performance" echo "2. If origin fast but CF slow: check Cloudflare connectivity" echo "3. For long processes: implement async/background jobs" echo "4. Consider Cloudflare Workers for extended timeout" echo "5. Use polling pattern for requests > 100 seconds" EOF

chmod +x /usr/local/bin/check-cf-524.sh

# Usage: /usr/local/bin/check-cf-524.sh example.com /api/endpoint ```

Cloudflare 524 Checklist

CheckCommandExpected
Direct origincurl originResponse < 100s
Through CFcurl https://domainResponse < 100s
Server resourcestop, freeAvailable
Database queriesSHOW PROCESSLISTNo slow queries
Error logsgrep timeoutNo timeout errors
Process designcode reviewAsync for long ops

Verify the Fix

```bash # After fixing 524 timeout

# 1. Test endpoint directly curl -I http://origin-ip/path // Response < 100 seconds

# 2. Test through Cloudflare curl -I https://example.com/path // HTTP 200, no 524

# 3. Check response time time curl https://example.com/path // Under 100 seconds

# 4. For long processes curl -X POST https://example.com/api/process // Returns task ID immediately

# 5. Monitor Cloudflare logs # Dashboard -> Analytics // No 524 errors

# 6. Load test ab -n 100 -c 10 https://example.com/path // All requests succeed ```

  • [Fix Cloudflare 522 Connection Timed Out](/articles/fix-cloudflare-522-connection-timed-out)
  • [Fix Cloudflare 521 Web Server Down](/articles/fix-cloudflare-521-web-server-down)
  • [Fix Cloudflare 523 Origin Unreachable](/articles/fix-cloudflare-523-origin-unreachable)