125 secondes, c'est le délai de lecture par défaut que la documentation Cloudflare annonce entre son proxy et votre serveur, relevé le 2 novembre 2026. Des pages de dépannage encore en ligne parlent de 100 secondes : ne construisez pas de diagnostic dessus.
Une erreur 524 signifie que Cloudflare a réussi à joindre le serveur d'origine, mais que celui-ci n'a pas fourni de réponse HTTP avant l'expiration de ce délai. Elle peut aussi signaler une écriture vers l'origine non terminée en 30 secondes. Pour trouver la requête, on ajoute $request_time, $upstream_header_time, $upstream_response_time et l'en-tête Cf-Ray au log nginx, puis on filtre sur la durée, pas sur le code HTTP : le 524 est produit par Cloudflare, votre serveur ne l'écrit pas.
Quand Cloudflare ne parvient pas à établir le contact, c'est un 522, avec ses propres causes.
La cascade des délais, couche par couche
Une requête traverse plusieurs chronomètres qui ne se connaissent pas. Le premier qui expire décide de ce que voit le visiteur, et du log où vous trouverez une trace.
| Couche | Délai | Défaut | À l'expiration |
| Cloudflare vers origine | Établissement TCP | 19 s | 522 |
| Cloudflare vers origine | Acquittement de la requête | 90 s | 522 |
| Cloudflare vers origine | Proxy Write Timeout | 30 s, non réglable | 524 |
| Cloudflare vers origine | Proxy Read Timeout | 125 s, réglable en Enterprise | 524 |
| nginx | proxy_read_timeout | 60 s | 504, mesuré plus bas |
| nginx | fastcgi_read_timeout | 60 s | Connexion FastCGI fermée |
| Apache | ProxyTimeout | Valeur de TimeOut, 60 s | Requête en échec |
| Gunicorn | timeout | 30 s | Worker silencieux tué et relancé |
| PHP | max_execution_time | 30 s | Script arrêté |
| PHP-FPM | request_terminate_timeout | 0, désactivé | Rien par défaut |
Gunicorn surveille le silence d'un worker : un worker non synchrone peut rester occupé sur une longue requête sans déclencher ce délai. PHP, dans son mode par défaut hors Windows (builds ZTS exclus depuis 8.3), mesure le temps processeur : ni les appels système ni les opérations de flux ne comptent. Un script bloqué en attente peut donc dépasser largement ses 30 secondes.
On en déduit ceci : avec un seul serveur amont muet et un nginx aux valeurs par défaut, nginx répond 504 à 60 secondes, et le chronomètre de Cloudflare n'arrive jamais à son terme. Un 524 sur ce type d'origine suppose donc un délai relevé, une reprise sur plusieurs serveurs, un flux retenu par le tampon de nginx ou un problème d'écriture. C'est un raisonnement, à confronter à votre configuration :
nginx -T 2>/dev/null | grep -E 'proxy_read_timeout|fastcgi_read_timeout|proxy_next_upstream'
L'exemple à 180 secondes de notre guide sur l'erreur 504 illustre le cas : derrière Cloudflare, il dépasse le délai par défaut et peut transformer un 504 en 524.
Ce que nginx écrit quand la réponse tarde
On a mesuré, sur nginx 1.30.6 en conteneur, devant un service Python qui dort le temps demandé. Le banc n'est pas derrière Cloudflare : un curl --max-time 125 joue le client qui abandonne. Les pages Cloudflare lues ne disent pas ce que devient la connexion vers l'origine après un 524. Ces lignes ne valent donc que pour nginx.
Notre guide du reverse proxy avancé propose déjà un format avec $request_time et $upstream_response_time. Pour ce diagnostic, il manque le temps d'en-tête et le Cf-Ray :
log_format timing '$time_iso8601 st=$status rt=$request_time '
'uct="$upstream_connect_time" uht="$upstream_header_time" '
'urt="$upstream_response_time" us="$upstream_status" '
'ray="$http_cf_ray" "$request"';
Les sorties du banc, horodatage retiré et commentaire ajouté par scénario :
# Délai nginx par défaut, requête de 130 s
st=504 rt=60.059 uct="0.000" uht="-" urt="60.060" us="504" ray="lab-A" "GET /default/slow?d=130 HTTP/1.1"
# Délai nginx relevé à 300 s, client qui abandonne à 125 s
st=499 rt=125.004 uct="0.001" uht="-" urt="125.004" us="-" ray="lab-B" "GET /relaxed/slow?d=130 HTTP/1.1"
# Délai nginx relevé à 300 s, client patient
st=200 rt=130.001 uct="0.000" uht="130.001" urt="130.001" us="200" ray="lab-C" "GET /relaxed/slow?d=130 HTTP/1.1"
# Délai par défaut, en-têtes immédiats puis un fragment toutes les 40 s
st=200 rt=120.008 uct="0.001" uht="0.002" urt="120.008" us="200" ray="lab-D" "GET /default/trickle?n=3&gap=40 HTTP/1.1"
L'horodatage du log est celui de la fin de la requête. Pour son début, soustrayez rt.
Chercher un code dans ce log n'aide pas : selon ce que le proxy fait de sa connexion, une même requête lente peut laisser un 499 ou un 200. On ne relie donc pas un 499 à un 524 sans preuve : on filtre sur la durée.
Le champ qui oriente la suite est uht. Un uht="-", ou proche de urt, indique que l'application n'a rien renvoyé pendant tout ce temps : cherchez une requête SQL ou un appel externe. Un uht très court avec un urt long indique une réponse qui commence vite et traîne ensuite : export en flux, tampon, client lent.
Retrouver la requête lente dans les logs de l'origine
Commencez par relever l'heure avec son fuseau et l'URL exacte, comme le demande la documentation Cloudflare, puis le Ray ID. Il se lit dans l'en-tête de réponse cf-ray, avec curl -v ou les outils de développement du navigateur.
Il faut ensuite journaliser les durées et Cf-Ray. Cloudflare transmet cet en-tête à l'origine, d'où le $http_cf_ray du format ci-dessus. Sous Apache, l'équivalent est %{CF-Ray}i, et %D pour la durée en microsecondes. Un Ray ID n'est pas garanti unique : comparez aussi l'URL et l'heure.
Dans ce format, rt est le troisième champ. Sur le log du banc, cette commande a sorti les cinq requêtes concernées, et le grep a isolé la bonne :
awk '{ split($3, a, "="); if (a[2] + 0 >= 100) print }' access.log
grep 'ray="lab-B"' access.log
Regardez aussi ce qui tourne encore : nginx n'écrit sa ligne qu'à la fin. Vingt secondes après le lancement de cinq requêtes, le log du banc ne contenait que la ligne de la requête de contrôle, alors que netstat -tn montrait cinq connexions ESTABLISHED vers le service. Pendant l'incident, un log muet ne prouve donc rien. L'error log montre chaque expiration amont (upstream timed out, niveau error), même pendant une reprise, mais l'abandon par le client y sort au niveau info, invisible avec un niveau notice ou error.
L'URL connue, on descend d'une couche et on active la trace du maillon suivant, avec un seuil bien inférieur à la limite. PHP-FPM a request_slowlog_timeout, à 0 par défaut ; une fois réglé, il écrit une pile d'appels dans le fichier slowlog, ce qui donne la ligne de code. Sur PostgreSQL, log_min_duration_statement vaut -1 par défaut, donc rien n'est journalisé : voir notre guide de performance PostgreSQL. MySQL garde son journal des requêtes lentes désactivé par défaut, avec long_query_time à 10 secondes : voir notre guide d'optimisation MySQL.
Sans accès shell à l'origine, Origin Analytics, dans le menu Speed, donne le temps de réponse par percentile et les chemins les plus lents. Son chronomètre s'arrête à la réception des en-têtes, et un dépassement y apparaît avec originResponseStatus à 0 et edgeResponseStatus à 524.
Trois serveurs amont et des délais par défaut : 180 secondes
On part d'un nginx sans aucun délai modifié, avec trois serveurs dans un bloc upstream. La valeur par défaut de proxy_next_upstream est error timeout : à chaque expiration, nginx repasse la requête au serveur suivant. proxy_next_upstream_timeout et proxy_next_upstream_tries valent 0, donc aucune limite.
st=504 rt=180.135 uct="0.001, 0.000, 0.000" uht="-, -, -" urt="60.061, 60.013, 60.062" us="504, 504, 504" ray="lab-E" "GET /multi/slow?d=300 HTTP/1.1"
st=499 rt=125.001 uct="0.000, 0.000, 0.000" uht="-, -, -" urt="60.037, 60.046, 4.919" us="504, 504, -" ray="lab-F" "GET /multi/slow?d=300 HTTP/1.1"
Trois fois 60 secondes font 180 secondes de silence, soit plus que les 125 de Cloudflare, sans le moindre proxy_read_timeout suspect dans la configuration. La signature se trouve dans les virgules de urt : grep -E 'urt="[^"]*, ' access.log les sort directement. Un POST déjà envoyé n'est pas rejoué depuis nginx 1.9.13, sauf option non_idempotent : sur le banc, un seul essai et un 504 à 60 secondes.
Le service voit passer le même travail trois fois. Son journal, pour une seule requête cliente :
19:14:30 port=8001 start /multi/slow?d=300 ray=lab-E
19:15:31 port=8002 start /multi/slow?d=300 ray=lab-E
19:16:31 port=8003 start /multi/slow?d=300 ray=lab-E
Et la coupure n'arrête rien. La requête lab-A, à laquelle nginx a répondu 504 à 60 secondes, a continué côté service jusqu'à 130 secondes, pour finir sur un Broken pipe en écrivant sa réponse. Cela vaut pour notre service de test : une application qui surveille sa connexion peut s'arrêter plus tôt.
Pour borner tout cela, on donne à chaque route longue un délai sous les 125 secondes, sans reprise, et on plafonne les reprises ailleurs :
location /exports/ {
proxy_pass http://app;
proxy_read_timeout 120s;
proxy_next_upstream off;
}
location /api/ {
proxy_pass http://app;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 100s;
}
Ce bloc passe nginx -t avec un upstream app à trois serveurs. Sur le banc, /exports/ répond 504 à 120 secondes après un seul essai. /api/ répond aussi à 120 secondes, après deux essais de 60 : proxy_next_upstream_timeout décide d'une nouvelle reprise, il ne coupe pas l'essai en cours.
Rester sous la limite a un effet : nginx répond lui-même, et son error log contient une ligne upstream timed out au niveau error, avec la requête et le serveur amont.
Le délai d'écriture de 30 secondes
Le délai d'écriture de 30 secondes ne se règle pas, selon la page dédiée au 524, et tombe à 6,5 secondes pour Cloudflare Images. On a simulé un envoi lent, coupé par le client à 30 secondes :
st=400 rt=29.999 uct="-" uht="-" urt="-" us="-" ray="lab-G" "PUT /relaxed/slow?d=1 HTTP/1.1"
Aucun serveur amont n'a été contacté : nginx recevait encore le corps de la requête. Cette ligne vient d'un client qui abandonne, sans Cloudflare devant, et ne dit rien de la cause. Elle indique quoi chercher : un PUT ou un POST autour de 30 secondes, sans valeur upstream.
Corriger un 524 sans toucher au délai de l'origine
La première piste sort le travail long de la requête HTTP : c'est le status polling de la documentation Cloudflare. L'application répond tout de suite, par exemple un 202 avec un identifiant de tâche, un worker travaille, le client interroge l'état puis télécharge le résultat.
Le délai côté Cloudflare ne se relève qu'en Enterprise, jusqu'à 6 000 secondes, par une Cache Rule si le contenu peut être mis en cache, ou par le paramètre proxy_read_timeout de la zone via l'API.
La page du 524 propose aussi un sous-domaine en DNS-only pour les grands exports. Celle sur le statut du proxy ajoute ce qu'elle ne dit pas : DNS-only n'y est recommandé que pour les enregistrements sans trafic web, et l'adresse IP de l'origine devient visible de quiconque interroge l'enregistrement. Un sous-domaine neuf évite d'attendre l'expiration d'un TTL en cache sur un nom existant. On réserve ce choix à une route interne ou authentifiée.
Et envoyer des octets pendant le traitement ? La page des Cache Rules définit le Proxy Read Timeout comme un délai entre deux lectures successives, celle du 524 parle d'une réponse HTTP non fournie. On n'a pas testé ce point derrière Cloudflare : à valider en préproduction. Côté nginx, c'est mesuré : avec le tampon actif par défaut, un fragment toutes les 10 secondes n'atteint le client qu'à la toute fin.
buffered http=200 ttfb=30.011579 total=30.011604
unbuffered http=200 ttfb=0.001373 total=30.005427
xaccel http=200 ttfb=0.000927 total=30.003879
Pour laisser sortir ces fragments, il faut proxy_buffering off sur la route (unbuffered) ou l'en-tête de réponse X-Accel-Buffering: no (xaccel).
Augmenter proxy_read_timeout sur l'origine ne corrige pas un 524 : ce réglage ne touche pas le chronomètre de Cloudflare. Au-delà de 125 secondes, il retire seulement le dernier délai qui vous donnait un message exploitable.
Note d'expérience de l'équipe SHPV Ops. Sur ce banc, le résultat qui compte est la reprise : un nginx sans aucun délai modifié dépasse les 125 secondes et lance trois fois le même travail. On en tire un réflexe : devant un dépassement, chercher les virgules dans upstream_response_time avant d'ouvrir la configuration.
Sources
- Cloudflare, Error 524 : définition, délais, plafond Enterprise, pistes.
- Cloudflare, Erreurs 5xx : heure, fuseau et URL à relever.
- Cloudflare, Connection limits : délais vers l'origine et code renvoyé pour chacun.
- Cloudflare, HTTP headers : envoi de
Cf-Rayà l'origine. - Cloudflare, Ray ID : lecture du Ray ID, unicité non garantie.
- Cloudflare, Cache Rules settings : délai défini entre deux lectures.
- Cloudflare, Origin Analytics : mesure jusqu'aux en-têtes, statuts d'origine et de bordure.
- Cloudflare, Proxy status : conséquences d'un enregistrement DNS-only.
- nginx, proxy : délais, reprises, tampon.
- nginx, upstream : variables de temps amont.
- nginx, log :
$request_time. - nginx, FastCGI :
fastcgi_read_timeout. - Apache, mod_proxy et core :
ProxyTimeout,TimeOut. - Apache, mod_log_config : formats de durée et d'en-tête.
- PHP-FPM, configuration : délais et
slowlog. - PHP, max_execution_time : ce que ce délai ne compte pas.
- Gunicorn, Settings :
timeout. - PostgreSQL 18, Logging :
log_min_duration_statement. - MySQL 8.4, Slow Query Log :
long_query_time.


