Le WordPress d'aujourd'hui, décodé pour les développeurs

Erreurs WordPress · Serveur et codes HTTP

Erreur 504 Gateway Timeout sur WordPress : solutions

HTTP 504

Erreur 504 Gateway Timeout sur WordPress : trouvez le script lent, réglez fastcgi_read_timeout, ProxyTimeout et PHP-FPM, ou découpez la tâche.

Message affiché

504 Gateway Timeout

En anglais : 504 Gateway Timeout

Réponse rapide

Le serveur frontal (nginx, Apache, CDN) a attendu PHP trop longtemps et a abandonné. Identifiez le script lent dans le journal, puis allongez les délais du proxy et de PHP, ou découpez la tâche en lots.

Après de longues secondes d’attente, le navigateur affiche « 504 Gateway Timeout » (« 504 Gateway Time-out » avec nginx). La page ne s’est pas chargée, mais ce n’est pas forcément un plantage : le serveur a continué de travailler pendant que son intermédiaire, lui, a cessé d’attendre. L’erreur apparaît le plus souvent sur une action longue : import, sauvegarde, génération de rapport, enregistrement d’une très grosse page, appel d’API externe.

Ce que signifie cette erreur

Une réponse 504 est émise par un passerelle ou proxy qui transmet votre requête à un serveur en amont et n’obtient pas de réponse dans le délai qui lui est imparti. WordPress est ici le serveur en amont : il n’a pas encore répondu, donc il ne peut pas avoir produit l’erreur lui-même (le libellé « Gateway Timeout » existe pourtant dans get_status_header_desc(), wp-includes/functions.php, comme dans la classe WP_Http pour les requêtes sortantes). Plusieurs maillons peuvent déclarer forfait :

  • nginx devant PHP-FPM : la directive fastcgi_read_timeout vaut 60 secondes par défaut, et le journal indique « upstream timed out (110: Connection timed out) while reading response header from upstream » ;
  • Apache avec mod_proxy_fcgi ou en proxy inverse : ce sont ProxyTimeout et Timeout qui comptent ;
  • Un CDN ou un répartiteur de charge : le délai est fixé chez eux, souvent plus court que le vôtre, et vos réglages serveur n’y changent rien ;
  • PHP lui-même : si max_execution_time ou request_terminate_timeout tranche avant le proxy, c’est une autre erreur qui s’affiche (voir la fiche temps d’exécution dépassé).

Un 504 se distingue du 502 (la réponse du serveur en amont est invalide ou la connexion est refusée) et du 503 (service indisponible ou saturé) : ici, la connexion est établie, mais la réponse n’arrive pas à temps.

Diagnostic rapide

Symptôme / constatCause probableÀ vérifier
Échec après une durée constante (60 s, 100 s…)Délai d’un proxy ou d’un CDN atteintChronométrer l’échec avec curl -w ; réglages nginx, Apache, CDN
Uniquement sur un import, une sauvegarde, un exportTâche longue exécutée dans la requête webDécouper en lots ou exécuter avec WP-CLI
Toutes les pages lentes puis 504Serveur saturé ou requête SQL lenteJournal des requêtes lentes PHP et MySQL ; charge du serveur
Échec uniquement quand une extension précise est activeAppel à une API externe qui ne répond pasJournal PHP, test de la requête sortante (fiche cURL 28)
504 avec la mention d’un CDN ou d’un WAFLe CDN n’a pas reçu de réponse de l’origineAccéder directement à l’origine, journal de l’origine
Le script va au bout malgré le 504Le travail continue après la coupure du proxyRésultat en base de données ; journal PHP-FPM

Les causes les plus fréquentes

  1. Une tâche trop longue exécutée dans une requête web : import de milliers de lignes, régénération de miniatures, sauvegarde.
  2. Un délai de proxy trop court par rapport au travail demandé (60 secondes par défaut sur nginx).
  3. Une requête externe qui ne répond pas : API de paiement, service d’e-mailing, serveur de licences, vérification de mises à jour.
  4. Une base de données lente ou verrouillée : requêtes sans index, tables énormes, options chargées automatiquement trop nombreuses.
  5. Un serveur sous-dimensionné ou saturé : les requêtes attendent un processus PHP libre.
  6. Un CDN ou un WAF dont le délai est plus court que celui de votre serveur.

Solutions pas à pas

Sauvegardez fichiers et base avant de toucher à la configuration, et testez-la avant de recharger un service (nginx -t ou apachectl configtest). Du moins invasif au plus technique :

1. Mesurer le délai et trouver le maillon

Un délai constant trahit un proxy : mesurez le temps écoulé jusqu’à l’échec.

curl -s -o /dev/null -w '%{http_code} en %{time_total} s\n' https://www.exemple.fr/wp-admin/admin-ajax.php?action=mon_action

Si l’échec survient toujours à la même seconde (60, 100, 120…), cherchez le réglage correspondant. Puis lisez le journal d’erreurs du serveur web à l’heure du test :

sudo tail -n 50 /var/log/nginx/error.log
sudo tail -n 50 /var/log/apache2/error.log

Pour croiser ces journaux avec ceux de PHP et de WordPress, l’article centraliser les logs nginx, PHP et WordPress détaille une méthode.

2. Alléger la tâche plutôt que d’allonger le délai

Allonger les délais masque le problème : une page qui met plus d’une minute à répondre bloque un processus PHP pendant tout ce temps. Quand c’est possible, traitez par lots (quelques dizaines d’éléments par appel, avec reprise), ou lancez la tâche en ligne de commande, qui n’a aucun proxy devant elle :

wp cron event run --due-now
wp media regenerate --yes
wp import export.xml --authors=skip

(wp import demande l’extension WordPress Importer.) La méthode de découpage est détaillée dans traiter 50 000 éléments sans timeout, et le cas d’un proxy amont trop court dans 504 Gateway Timeout sur un import volumineux.

3. Allonger les délais de nginx

Limitez l’allongement à la zone concernée plutôt qu’à tout le site :

# bloc server : uniquement l'administration
location ^~ /wp-admin/ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_read_timeout 300s;
    fastcgi_send_timeout 300s;
}

Adaptez le nom de l’include et le socket à votre installation, puis sudo nginx -t && sudo systemctl reload nginx. Si nginx est lui-même derrière un autre proxy, réglez aussi proxy_read_timeout sur celui-ci.

4. Allonger les délais d’Apache

# dans le VirtualHost
ProxyTimeout 300
Timeout 300

ProxyTimeout s’applique aux échanges avec PHP-FPM via mod_proxy_fcgi ; Timeout (300 par défaut sous Debian) borne les entrées-sorties de la connexion. Rechargez avec sudo systemctl reload apache2.

5. Aligner PHP sur le proxy

Un délai de proxy plus long ne sert à rien si PHP coupe avant. Alignez la limite de PHP et celle du pool PHP-FPM :

; php.ini ou .user.ini
max_execution_time = 300

; pool PHP-FPM (ex. /etc/php/8.2/fpm/pool.d/monsite.conf)
request_terminate_timeout = 300s

Sur un mutualisé, ces valeurs se règlent dans le panneau (rubrique PHP) ou via .user.ini à la racine du site. Rechargez PHP-FPM : sudo systemctl reload php8.2-fpm.

6. Trouver le script ou la requête lente

Dans le pool PHP-FPM, activez le journal des requêtes lentes : il écrit la pile d’appels des scripts qui dépassent le seuil.

request_slowlog_timeout = 10s
slowlog = /var/log/php8.2-fpm-slow.log

Côté base de données, activez le journal des requêtes lentes de MySQL ou MariaDB (slow_query_log et long_query_time), ou installez temporairement l’extension Query Monitor pour voir quelle requête, quel crochet ou quel appel HTTP prend le temps.

7. Si un CDN ou un WAF est devant

Testez en contournant le CDN (accès direct à l’IP d’origine avec un en-tête Host, ou en désactivant temporairement le proxy). Si l’erreur disparaît, le délai du CDN est en cause : il est souvent fixe selon l’offre (de l’ordre de 100 secondes chez certains), donc la seule vraie solution est de rendre la tâche plus courte ou de la lancer hors requête web.

Prévenir l’erreur

  • Ne lancez jamais une tâche de plusieurs minutes dans une requête web : planifiez-la avec un cron système ou découpez-la en lots avec reprise.
  • Donnez un délai explicite aux appels sortants (wp_remote_get() avec timeout) pour qu’une API externe lente ne bloque pas la page.
  • Gardez le journal des requêtes lentes de PHP-FPM actif : il signale la dérive avant l’incident.
  • Surveillez la taille de la table des options et des tables volumineuses, et ajoutez les index manquants.
  • Documentez les délais de chaque maillon (CDN, proxy, PHP) pour savoir lequel ajuster.
Puis-je simplement mettre un délai énorme ?

Techniquement oui, mais c’est déconseillé : chaque requête longue immobilise un processus PHP, et quelques-unes suffisent à saturer le site. Réservez l’allongement à une zone précise (l’administration, une route d’import) et préférez découper la tâche.

Le travail s’est-il quand même terminé malgré l’erreur 504 ?

Souvent oui : le proxy abandonne la connexion, mais PHP continue jusqu’à sa propre limite. Vérifiez le résultat (articles importés, fichier généré) avant de relancer, sous peine de créer des doublons.

Pourquoi la 504 revient-elle avec un hébergement qui n’affiche aucun réglage ?

Sur un mutualisé, les délais sont fixés par l’hébergeur. Demandez-lui la valeur appliquée à votre offre, ou exécutez la tâche avec WP-CLI si l’accès SSH est disponible.

La 504 est-elle liée à un appel externe ?

Elle peut l’être : si WordPress attend une API qui ne répond pas, la page entière attend. Dans ce cas, le journal montre souvent aussi l’erreur cURL 28.