TL;DRUne erreur 504 signifie qu'un serveur intermédiaire (proxy, reverse proxy, CDN) n'a pas reçu de réponse à temps de la part du serveur qu'il interrogeait. Voici le mécanisme exact, les délais à connaître et une méthode de diagnostic pour la résoudre.

Que signifie vraiment une erreur 504 Gateway Timeout ?#

Le code 504 appartient à la famille des erreurs serveur (5xx). Selon la documentation MDN, il indique qu'un serveur agissant comme passerelle ou proxy n'a pas reçu de réponse à temps du serveur en amont dont il avait besoin pour traiter la requête. La nuance avec la 502 Bad Gateway est importante : avec une 502, le proxy a reçu une réponse invalide ; avec une 504, il n'a reçu aucune réponse HTTP dans le délai imparti.

Le mot clé est donc délai. Une 504 n'est jamais produite par un serveur qui travaille seul : elle suppose au moins deux maillons, l'un qui attend, l'autre qui tarde. Trouver la cause revient à répondre à deux questions : qui attend, et pourquoi l'autre est-il si long ?

La chaîne de composants : qui attend qui ?#

Une requête web traverse souvent plusieurs couches, chacune avec son propre chronomètre :

  1. le navigateur du visiteur ;
  2. un CDN ou un pare-feu applicatif, par exemple Cloudflare ;
  3. un serveur web frontal (nginx ou Apache) ;
  4. un gestionnaire d'application, typiquement PHP-FPM pour un site PHP, ou un serveur Node, Python, Java ;
  5. des services derrière l'application : base de données, API tierces, moteur de recherche, file de messages.

Une 504 apparaît quand l'un de ces maillons cesse d'attendre le suivant. Le chronomètre qui expire en premier détermine qui affiche l'erreur. C'est ce qui rend le diagnostic délicat : la page d'erreur vue par le visiteur est celle du composant le plus proche de lui qui a perdu patience, pas celle du composant réellement en cause.

Les délais à connaître, composant par composant#

nginx en reverse proxy#

Quand nginx transmet la requête à un autre serveur avec proxy_pass, trois directives du module proxy encadrent l'échange. Leur valeur par défaut est de 60 secondes :

proxy_connect_timeout 60s;  # établissement de la connexion (ne dépasse généralement pas 75 s)
proxy_send_timeout    60s;  # envoi de la requête vers l'amont, entre deux écritures
proxy_read_timeout    60s;  # attente de la réponse, entre deux lectures

Le point souvent mal compris : proxy_read_timeout ne mesure pas la durée totale de la réponse, mais l'intervalle entre deux opérations de lecture successives. Un serveur qui envoie un octet toutes les 30 secondes ne déclenche donc pas le délai, alors qu'un serveur silencieux pendant 61 secondes le déclenche.

nginx avec PHP-FPM (FastCGI)#

Pour un site PHP servi par PHP-FPM via fastcgi_pass, ce sont les directives équivalentes du module FastCGI qui s'appliquent, également à 60 secondes par défaut :

fastcgi_connect_timeout 60s;
fastcgi_send_timeout    60s;
fastcgi_read_timeout    60s;

Elles se règlent aux niveaux http, server ou location, ce qui permet d'augmenter la tolérance sur une seule route (un export, par exemple) sans toucher au reste du site.

Apache en reverse proxy#

Avec mod_proxy, la directive ProxyTimeout fixe le délai réseau des requêtes proxifiées. Sa valeur par défaut est celle de la directive Timeout du serveur. Son objectif, selon la documentation, est précisément d'éviter d'attendre indéfiniment un serveur d'application qui se bloque. Le paramètre timeout de ProxyPass (délai de socket avec l'arrière-plan) et connectiontimeout (délai de connexion) permettent un réglage plus fin :

ProxyTimeout 60
ProxyPass /api http://127.0.0.1:8080/api connectiontimeout=5 timeout=30

PHP et PHP-FPM#

Deux réglages côté PHP interviennent, et ils se comportent différemment :

  • max_execution_time : 30 secondes par défaut pour PHP servi par le web (0, donc illimité, en ligne de commande). Sur Linux, le temps passé dans des appels système, des flux ou des requêtes vers la base n'est pas décompté de cette limite, sauf en cas de compilation avec les timers d'exécution Zend. Un script bloqué sur une requête SQL peut donc dépasser largement les 30 secondes affichées.
  • request_terminate_timeout dans la configuration du pool PHP-FPM : délai après lequel le processus qui sert une requête est tué, utile quand max_execution_time n'arrête pas le script. Sa valeur par défaut est 0 (désactivé).
; pool PHP-FPM
request_terminate_timeout = 120s
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm/slow.log

La directive request_slowlog_timeout (désactivée par défaut) est précieuse en diagnostic : au-delà du délai indiqué, PHP-FPM écrit dans le fichier slowlog la trace d'appel du script lent, ce qui désigne directement la fonction qui bloque.

Cloudflare#

Lorsque votre site passe par Cloudflare, deux erreurs voisines coexistent. La 504 signale que Cloudflare n'arrive pas à établir le contact avec votre serveur d'origine, ou que celui-ci renvoie lui-même une 504 que Cloudflare habille de sa page. L'erreur 524 est différente : Cloudflare a réussi à se connecter, mais l'origine n'a pas fourni de réponse HTTP dans le délai de lecture, fixé à 125 secondes par défaut. Cloudflare indique que les clients Enterprise peuvent l'augmenter. Une requête qui dure plus de deux minutes doit donc être repensée, pas simplement tolérée.

Cloudflare précise aussi que les erreurs provenant de votre origine s'affichent avec la page de marque Cloudflare, alors que celles produites par Cloudflare lui-même s'affichent en page blanche sans marque. Cette différence aide à savoir de quel côté chercher.

Méthode de diagnostic, dans l'ordre#

1. Identifier quel composant répond 504#

Testez l'URL en contournant les couches une à une. Depuis le serveur, interrogez directement le serveur web ou l'application, puis comparez avec l'URL publique :

curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' http://127.0.0.1/chemin-lent
curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' https://exemple.fr/chemin-lent

Si le test local répond correctement mais lentement, l'application est en cause. Si le test local échoue aussi, le problème est plus bas dans la chaîne. Si seul le test public échoue, regardez le CDN, le pare-feu et le réseau.

2. Lire les journaux du proxy#

Le journal d'erreurs de nginx ou d'Apache indique quel délai a expiré et vers quelle adresse en amont. Repérez l'heure exacte de l'erreur, l'URL concernée et la mention de timeout. C'est la donnée qui oriente tout le reste.

3. Vérifier l'état du serveur d'application#

Pour PHP-FPM, contrôlez que le pool n'est pas saturé : la limite pm.max_children fixe le nombre de requêtes simultanées servies. Une fois cette limite atteinte, les nouvelles requêtes patientent dans la file et finissent par expirer côté proxy. Activez le slowlog évoqué plus haut pour voir où les scripts s'attardent.

4. Mesurer la requête réellement lente#

Isolez ensuite le traitement fautif : requête SQL sans index, boucle sur un grand nombre d'enregistrements, appel HTTP sortant vers un service tiers sans délai maximal, génération d'un fichier volumineux. Le journal des requêtes lentes de la base de données complète le slowlog PHP.

5. Regarder la charge machine#

Mémoire saturée, swap, disque plein ou processeur à 100 % ralentissent tout. Vérifiez aussi si l'erreur coïncide avec une tâche planifiée, une sauvegarde ou un pic de trafic.

Cinq scénarios types#

Scénario 1 : une requête SQL qui devient lente avec le volume#

Une page de liste fonctionnait avec quelques centaines de lignes, puis ralentit quand la table grossit, faute d'index sur la colonne filtrée. La requête dépasse 60 secondes, nginx cesse d'attendre PHP-FPM et le visiteur voit une 504. Le correctif est l'index ou la réécriture de la requête, pas l'augmentation de fastcgi_read_timeout.

Scénario 2 : un pool PHP-FPM saturé#

Un pic de trafic ou quelques requêtes très longues occupent tous les processus du pool. Les requêtes suivantes attendent leur tour et expirent. Le symptôme est intermittent et corrélé à la charge. Les pistes : identifier les scripts lents, dimensionner pm.max_children selon la mémoire réellement disponible, mettre en cache les pages coûteuses.

Scénario 3 : un appel à une API externe sans limite de temps#

Le site interroge un service tiers (paiement, transporteur, CRM) pendant l'affichage de la page. Quand ce service ralentit, votre page ralentit avec lui. Il faut définir un délai maximal explicite sur l'appel sortant, prévoir un comportement de repli et, quand c'est possible, sortir l'appel de la requête web.

Scénario 4 : un export ou un import lancé depuis le navigateur#

Un bouton déclenche en direct la génération d'un gros fichier ou l'import de milliers de lignes. Le traitement dure plus de 60 secondes côté nginx, ou plus de 125 secondes côté Cloudflare, qui affiche alors une erreur 524. La bonne architecture consiste à lancer le travail en arrière-plan (file de tâches ou commande planifiée), puis à interroger son avancement ou à notifier l'utilisateur à la fin.

Scénario 5 : le serveur d'origine ne répond plus du tout#

Le service PHP-FPM est arrêté, le serveur est saturé en mémoire, un pare-feu bloque les adresses de Cloudflare ou le serveur d'origine est injoignable. Cloudflare ne parvient pas à établir le contact et affiche sa 504. Ici, aucun délai à ajuster : il faut remettre l'origine en service et vérifier que les adresses du CDN sont bien autorisées.

Faut-il augmenter les timeouts ?#

C'est le réflexe le plus courant, et souvent le moins bon. Augmenter proxy_read_timeout ou fastcgi_read_timeout a un sens dans un cas précis : une opération légitimement longue et rare, identifiée, sur une route dédiée. On l'applique alors à un bloc location ciblé :

location = /admin/export {
    fastcgi_pass unix:/run/php/php-fpm.sock;
    include fastcgi_params;
    fastcgi_read_timeout 300s;
}

Dans tous les autres cas, allonger le délai a des effets pervers : les processus PHP restent occupés plus longtemps, le pool sature plus vite et l'erreur revient, plus grave. Gardez aussi à l'esprit la chaîne complète : porter nginx à 300 secondes ne sert à rien derrière Cloudflare, qui abandonne à 125 secondes.

Avant de vérifier un réglage, appliquez la règle de prudence habituelle : testez la syntaxe de la configuration (nginx -t, apachectl configtest ou php-fpm -t selon la version installée) avant tout rechargement.

Côté visiteur ou côté serveur ?#

Dans l'immense majorité des cas, une 504 est un problème de serveur : par définition, la chaîne côté site a perdu patience. Le visiteur peut essayer d'actualiser la page après quelques instants, car certaines 504 sont transitoires, comme le rappelle MDN.

Un problème côté visiteur n'est plausible que si le site fonctionne normalement pour d'autres personnes. Dans ce cas, vérifiez le réseau, le pare-feu, les paramètres de proxy ou de VPN et la configuration DNS de votre poste, comme le suggère MDN. Si vous êtes le seul concerné, testez depuis un autre réseau, par exemple en partage de connexion mobile : si le site s'affiche, le problème est local.

Prévenir les 504 sur la durée#

  • Superviser les temps de réponse, la saturation du pool PHP-FPM et la charge machine, pour agir avant l'erreur.
  • Activer le slowlog PHP et le journal des requêtes lentes de la base de données en permanence.
  • Mettre en cache les pages et résultats coûteux plutôt que de les recalculer à chaque visite.
  • Déporter les traitements longs dans des tâches asynchrones.
  • Imposer un délai maximal à chaque appel sortant vers un service externe.

Si votre site est sur un hébergement mutualisé, vous n'avez souvent pas accès à la configuration nginx ni aux journaux du proxy : le diagnostic passe alors par le support de l'hébergeur. Sur un serveur dédié ou un VPS, vous maîtrisez ces réglages, mais vous en portez aussi la maintenance ; nous proposons chez Websource, agence web à Aix-en-Provence, un hébergement web avec infogérance de serveurs qui prend en charge ce suivi.

Différencier la 504 des autres erreurs 5xx#

Pour ne pas chercher au mauvais endroit, retenez ces repères. Une erreur 500 signale une défaillance interne de l'application. Une 502 indique une réponse invalide de l'amont. Une 503 traduit une indisponibilité, souvent temporaire ou volontaire. La 504, elle, concerne uniquement l'absence de réponse dans les délais. Les journaux d'erreurs du proxy nomment généralement le délai expiré : c'est le meilleur moyen de trancher.

Questions fréquentes#

Quelle est la différence entre une erreur 502 et une erreur 504 ?#

Avec une 502 Bad Gateway, le proxy a reçu une réponse invalide du serveur en amont. Avec une 504 Gateway Timeout, il n'a reçu aucune réponse HTTP dans le délai imparti. La 504 est donc un problème d'attente, la 502 un problème de réponse.

Quel est le délai par défaut de nginx avant une erreur 504 ?#

Les directives proxy_read_timeout et fastcgi_read_timeout valent 60 secondes par défaut. Ce délai mesure l'attente entre deux lectures successives sur la connexion vers l'amont, pas la durée totale de la réponse. Il peut être modifié aux niveaux http, server ou location.

Quelle est la différence entre les erreurs Cloudflare 504 et 524 ?#

La 504 indique que Cloudflare n'arrive pas à établir le contact avec le serveur d'origine, ou que l'origine renvoie elle-même une 504. La 524 signifie que la connexion a réussi mais que l'origine n'a pas répondu dans le délai de lecture, de 125 secondes par défaut.

Augmenter max_execution_time règle-t-il une erreur 504 ?#

Rarement. Sa valeur par défaut est de 30 secondes pour PHP servi par le web, et sur Linux le temps passé en requêtes SQL ou en appels réseau n'y est pas décompté. La 504 dépend surtout des délais du proxy ; il vaut mieux corriger la lenteur que repousser les limites.

Une erreur 504 vient-elle de mon ordinateur ou de ma connexion ?#

C'est peu probable : une 504 est produite par un intermédiaire côté site. Si le site fonctionne pour d'autres personnes, vérifiez toutefois votre réseau, votre VPN, vos paramètres de proxy et votre DNS. Réessayer plus tard suffit souvent quand l'incident est transitoire.

Article rédigé le 29/09/2026 par l'équipe Websource à partir des sources citées ci-dessus, puis relu avant publication. Une information vous semble inexacte ou datée ? Signalez-le nous, nous corrigeons.