---
title: "504 Gateway Timeout: Causes and Fixes Behind a CDN"
description: Learn the causes of a 504 Gateway Timeout behind a CDN and how to fix origin timeouts, 504 errors, and gateway timeout issues.
---

[Content Delivery Network Blog](https://blog.blazingcdn.com/en-us)

# [504 Gateway Timeout: Causes and Fixes Behind a CDN](https://blog.blazingcdn.com/en-us/504-gateway-timeout-causes-and-fixes-behind-a-cdn)

 Written by [Vadym Borovskyi](https://blog.blazingcdn.com/en-us/author/blazingcdn) | Nov 2, 2026, 7:58:02 AM

A **504 Gateway Timeout** behind a CDN means one proxy in the chain (the CDN edge, an origin shield, a load balancer or a reverse proxy) waited for the next hop longer than its configured limit and gave up. The fix is rarely "raise the timeout." It is finding which hop fired, making each inner timeout shorter than the one outside it, and taking slow work off the request path. Plan on about 60 to 90 minutes to diagnose and fix a typical stack with the steps below.

As of 2026, Amazon CloudFront waits 30 seconds by default for an origin response before returning a 504 Gateway Timeout, nginx waits 60 seconds (its proxy\_read\_timeout default), and Cloudflare waits 100 seconds but reports the failure as its own 524 status instead of a 504. The duration of a failed request is therefore the fastest clue to which layer produced the error.

## **Which layer returned the 504 gateway timeout?**

The layer that returned the 504 is the one whose timeout expired first, and you can usually identify it from two signals: how long the request took before failing, and which response headers came back. A failure at almost exactly 30.0 seconds with a CDN error header points at the edge. A failure at 60 seconds with a plain server banner points at your own reverse proxy.

Per RFC 9110, a 504 means a server acting as a gateway or proxy did not receive a timely response from an upstream server. Every hop between the user and your application can generate one, which is why a gateway timeout behind a CDN is a chain problem first and an application problem second.

| Time to failure | Status and header signal | Most likely emitter (default settings) |
| --- | --- | --- |
| About 30 s | 504, X-Cache reads "Error from cloudfront" | Amazon CloudFront origin response timeout |
| About 30 s | 504 or 502 from a Google front end | Google Cloud load balancer backend service timeout |
| About 60 s | 504, Server header shows nginx | nginx proxy\_read\_timeout or fastcgi\_read\_timeout |
| About 60 s | 504, Server header shows awselb | AWS Application Load Balancer idle timeout |
| About 100 s | 524, cf-ray header present | Cloudflare proxy read timeout |
| Under 1 s | 504 with an application-branded body | Your app proxying to an internal service that already timed out |

If the time to failure matches a known default to within a second, you have found the hop that fired, and the real cause sits one hop further inward.

## **Prerequisites**

- Access to CDN logs or real-time statistics that show status codes and origin response time per request.
- Reverse proxy access logs with upstream response time enabled (in nginx, add the upstream\_response\_time and request\_time variables to the log format).
- An HTTP client that can print time to first byte and total time, and that can send a request straight to the origin IP with the production Host header.
- Application metrics with p50, p95 and p99 latency per route.

## **How to fix a 504 error behind a CDN, step by step**

1. **Reproduce and time one failing request through the CDN.** Record total duration, status, Server, Via, X-Cache and any CDN request ID header. Why: the duration plus headers identify the emitter using the table above.
2. **Repeat the same request directly against the origin.** Point your client at the origin IP or internal load balancer, keep the Host header, and record time to first byte. Why: if the origin answers in 45 seconds directly, the CDN is only reporting the problem, not causing it.
3. **Write down every timeout in the chain.** For each hop list the connect timeout, the read or response timeout, and the idle keep-alive timeout. Why: most recurring 504s come from timeouts set independently by different teams, with no ordering between them.
4. **Order request timeouts so they shrink inward.** Each hop must give up before the hop outside it does, with a margin of a few seconds. Why: if the CDN abandons a request at 30 seconds while nginx waits 60 and the app waits 120, the origin keeps burning a worker for 90 seconds on a response nobody will receive.
5. **Order idle keep-alive timeouts so they grow inward.** The upstream server must keep idle connections open longer than the proxy in front of it. Why: if Node.js closes idle sockets at its 5-second keepAliveTimeout default while an AWS Application Load Balancer reuses them for 60 seconds, the balancer sends requests into closed sockets and you get intermittent 502s that look like 504 noise in dashboards.
6. **Set the database statement timeout below the app timeout.** Why: a query that runs past the app deadline holds a connection pool slot, and pool exhaustion is the most common way one slow query becomes a site-wide 504 storm.
7. **Take long work off the synchronous path.** Any endpoint whose p99 exceeds half of the edge timeout should return 202 Accepted with a job ID and let the client poll, or stream bytes early. Why: report exports, video packaging and bulk imports do not belong inside a 30-second proxy budget.
8. **Shield and coalesce the origin.** Enable an origin shield tier and request coalescing so concurrent misses for one object collapse into a single origin fetch, and send Cache-Control with stale-while-revalidate and stale-if-error (RFC 5861) where your CDN honors them. Why: an expired popular object with 2,000 concurrent requests becomes 2,000 origin fetches without coalescing and one fetch per shield with it.

### A worked timeout ladder

The pattern below is this blog's suggested starting ladder for an API or HTML origin behind a CDN. It keeps a 5-second margin between hops so the inner layer always fails first and returns a clean error the outer layer can pass through.

| Hop | Request timeout | Idle keep-alive timeout | Example setting |
| --- | --- | --- | --- |
| CDN edge to origin | 60 s | vendor-managed | CloudFront origin response timeout raised from 30 to 60 |
| Load balancer | 55 s | 55 s | ALB idle timeout 55 |
| Reverse proxy | 50 s | 65 s | nginx proxy\_read\_timeout 50s, proxy\_connect\_timeout 5s, keepalive\_timeout 65s |
| Application | 45 s | 70 s | Gunicorn timeout 45, or Node.js keepAliveTimeout 70000 ms with headersTimeout above it |
| Database | 40 s | pool-managed | PostgreSQL statement\_timeout 40s |

Request timeouts must decrease as you move inward while idle keep-alive timeouts must increase, and most recurring 504 and 502 incidents violate one of those two orderings.

One nuance changes how you read these numbers. The nginx proxy\_read\_timeout applies between two successive reads from the upstream, not to the whole response, and Amazon CloudFront's origin response timeout likewise covers the wait between packets. An origin that sends headers and the first chunk within 2 seconds can stream a 5-minute export without tripping either limit, which is why streaming early bytes is a legitimate fix and not a hack.

### Why an origin timeout turns into a 504 storm

Little's law explains the cliff. Requests in flight equal arrival rate multiplied by latency. Take an origin with 64 worker slots and a p50 latency of 100 ms: it sustains 64 / 0.1 = 640 requests per second. If a dependency slows each request to 30 seconds, capacity collapses to 64 / 30, about 2.1 requests per second.

Everything above 2.1 requests per second now queues, waits out the edge timeout and becomes a 504. If the CDN also retries timed-out GET requests (Amazon CloudFront makes up to 3 connection attempts by default), worst-case time to a 504 on a dead origin with a 10-second connect timeout is 3 × 10 = 30 seconds of connection attempts alone, and retried reads add load to an origin that is already saturated. This is why raising timeouts during an incident usually makes it worse: longer waits mean more requests in flight per worker.

For heavy static workloads the cheapest origin timeout is the one that never reaches the origin. BlazingCDN includes origin shield and request coalescing on every plan and sets up zones and cache rules together with an engineer, so the [**origin shield and request coalescing features**](https://blazingcdn.com/features/) that absorb miss storms are configured at onboarding rather than after the first incident.

## **How to validate the fix**

- **Edge 504 rate.** Chart 504s as a share of all responses per minute. A reasonable target (this blog's suggestion, not a standard) is under 0.01 percent outside deploys.
- **Time-to-failure histogram.** Remaining 504s should cluster at the innermost timeout (40 to 45 seconds in the ladder above), not at the edge limit. A cluster at the edge value means an inner hop is still waiting longer than it should.
- **Origin p99 versus edge timeout.** Origin p99 latency per route should stay below 50 percent of the edge timeout. A route at 70 percent will 504 under the next load spike.
- **Origin request rate during a purge.** Purge one popular object and watch origin requests for it. With coalescing working, you should see one fetch per shield location, not one per edge request.
- **Upstream response time in proxy logs.** Compare request\_time with upstream\_response\_time. A large gap means time is lost in the proxy queue, not the application.

## **Rollback**

Change one hop at a time and keep the previous value in your change ticket. If 502s rise after a keep-alive change, revert that hop first, since a mismatched idle timeout produces connection resets within minutes. If 504s rise after shortening an inner timeout, the route genuinely needs more time: restore the old value for that route only and schedule it for the async pattern in step 7.

## **Common gateway timeout CDN failure modes**

- **Symptom:** 504s only on cache misses after a deploy or purge. **Cause:** cold cache sending full traffic to an origin sized for a 95 percent hit ratio. **Fix:** warm the cache through the CDN API before the purge, enable coalescing, and stagger purges.
- **Symptom:** 504s at exactly the CDN default on one route. **Cause:** a synchronous report or upload handler. **Fix:** 202 Accepted plus polling, or stream the first bytes immediately.
- **Symptom:** intermittent 502s mixed with 504s at low traffic. **Cause:** app keep-alive shorter than the load balancer idle timeout. **Fix:** raise the app keep-alive above the balancer value.
- **Symptom:** all routes 504 at once while CPU is idle. **Cause:** database or HTTP client pool exhausted by one slow dependency. **Fix:** per-dependency timeouts, a circuit breaker, and a statement timeout below the app timeout.
- **Symptom:** Cloudflare shows 524, origin logs show 200. **Cause:** the origin finished after the 100-second proxy limit. **Fix:** the same async pattern; the 200 in your logs was delivered to nobody.

## **Tuning once the 504s stop**

Set timeouts per route, not per host. Health checks and static assets deserve a 5 to 10 second budget, while a known export endpoint can carry a longer one behind its own location block. Keep connect timeouts short (2 to 5 seconds inside a region): a TCP handshake that takes longer than that is a dead host, and failing fast lets the proxy try the next upstream.

The honest trade-off: shorter timeouts convert slow successes into fast failures. That is the right call for interactive traffic and the wrong one for a batch client that would happily wait 90 seconds. Know which clients you serve before you tighten the ladder, and give batch consumers a separate hostname with its own limits.

## **FAQ: 504 Gateway Timeout behind a CDN**

### What is the difference between a 502 and a 504 error behind a CDN?

A 504 means the proxy received no response from upstream within its timeout, while a 502 means it received an invalid response or a broken connection. Behind a CDN, 504s usually trace to slow origins or exhausted worker pools, whereas 502s often trace to keep-alive mismatches, TLS failures or a crashed upstream process returning a reset.

### Should I just increase the CDN origin timeout to fix a 504 gateway timeout?

Raising the CDN origin timeout rarely fixes a recurring 504 gateway timeout. It holds more requests in flight per worker, which lowers effective origin capacity during the exact moments the origin is slow. Increase it only for specific routes that legitimately need longer, after ordering the inner timeouts so each hop fails before the one outside it.

### Why does Cloudflare show a 524 instead of a 504 for an origin timeout?

Cloudflare uses its own 524 status when the origin accepts the connection but does not respond within the 100-second proxy read limit. A 504 seen through Cloudflare usually originated at your own load balancer or reverse proxy. That distinction tells you whether the timeout fired at the Cloudflare edge or inside your infrastructure.

### How do I find which proxy returned the 504 error?

Measure how long the failing request took and read the response headers. A duration matching a known default, such as 30 seconds for Amazon CloudFront or 60 seconds for nginx, plus headers like X-Cache or Server, identifies the emitting hop. Then request the origin directly with the same Host header to measure its real latency.

## **Audit your timeout ladder this week**

Pull every 504 from the last 7 days and plot time to failure as a histogram. Each spike sits at some layer's timeout; label it, then list the request and keep-alive timeouts for every hop and check both orderings. Any route whose p99 exceeds half your edge timeout goes on the async backlog. The exercise takes an afternoon and usually explains months of intermittent gateway timeouts.

If your heavy traffic is video, software downloads or large static files, BlazingCDN runs a 14-day testing period on real production traffic at $5 per TB with the monthly minimum waived, and its [**Anycast CDN with origin shield in front of your origin**](https://blazingcdn.com/anycast-cdn/) is the place to start.

[View full post](https://blog.blazingcdn.com/en-us/504-gateway-timeout-causes-and-fixes-behind-a-cdn)

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Vadym Borovskyi"
  },
  "dateModified" : "2026-11-02T07:58:02.627Z",
  "datePublished" : "2026-11-02T07:58:02Z",
  "headline" : "504 Gateway Timeout: Causes and Fixes Behind a CDN",
  "image" : {
    "@type" : "ImageObject",
    "height" : 768,
    "url" : "https://143144902.fs1.hubspotusercontent-eu1.net/hubfs/143144902/Gemini-Blog/image-Nov-02-2026-07-55-36-2777-AM.jpeg",
    "width" : 1376
  },
  "mainEntityOfPage" : "https://blog.blazingcdn.com/en-us/504-gateway-timeout-causes-and-fixes-behind-a-cdn",
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "height" : 60.0,
      "url" : "https://143144902.fs1.hubspotusercontent-eu1.net/hubfs/143144902/Logo%20b-3.png",
      "width" : 245.85367
    },
    "name" : "CDN Blog"
  }
}
```