504 Gateway Timeout. C’est tout ce que le navigateur affiche après un import de fiches produit qui tournait sans problème la veille sur un jeu de test plus petit. Pas de trace dans les journaux WordPress, rien dans debug.log, et pourtant l’import échoue systématiquement au bout d’un temps qui semble toujours identique à quelques secondes près.
Ce symptôme précis, un blocage qui survient toujours au même instant quel que soit le volume réellement traité, est presque toujours la signature d’un délai imposé en amont de PHP, et non d’une limite PHP elle-même. C’est la confusion la plus fréquente sur ce type d’incident.
Symptôme : un échec qui ne dépend pas du script
Le réflexe naturel consiste à augmenter max_execution_time dans php.ini ou à ajouter set_time_limit( 300 ) en tête du script d’import. Si le comportement ne change pas d’un iota, c’est le premier indice sérieux : quelque chose coupe la connexion avant même que PHP n’ait la possibilité d’aller au bout de son propre délai configuré.
Un test simple permet de confirmer l’hypothèse : lancer l’import en arrière-plan via WP-CLI, sans passer par le navigateur ni par le serveur web front :
wp eval-file import-produits.php --url=exemple.fr > import.log 2>&1 &
Si l’import se termine sans erreur exécuté de cette façon, la cause n’est ni dans le script, ni dans la configuration PHP : elle se situe entre le navigateur et PHP-FPM.
Diagnostic : identifier la couche qui coupe
Une architecture WordPress moderne empile souvent plusieurs relais entre le visiteur et le processus PHP : un CDN ou un pare-feu applicatif en frontal, un serveur web (Nginx le plus souvent) qui fait office de reverse proxy, puis PHP-FPM. Chacune de ces couches peut porter son propre délai d’attente, indépendamment des réglages PHP.
- Le CDN ou le WAF en frontal impose fréquemment un délai fixe, souvent proche de trente secondes, non documenté dans l’interface d’administration du site ;
- Nginx applique par défaut
proxy_read_timeout 60ssur le bloc qui transmet la requête vers PHP-FPM ; - PHP-FPM lui-même possède un
request_terminate_timeoutqui, s’il est actif, tue le processus indépendamment demax_execution_time.

Correctif : aligner les délais sur toute la chaîne
Modifier un seul maillon ne suffit presque jamais. Le correctif efficace consiste à relever le délai à chaque étage, dans le bon ordre, en commençant par le plus proche de PHP :
; php-fpm pool
request_terminate_timeout = 300
# bloc serveur nginx
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 300;
}
Si un CDN ou un pare-feu applicatif est présent devant le serveur, il faut vérifier sa propre limite dans son tableau de bord : elle prime souvent sur tout ce qui est configuré plus bas, et aucune modification côté serveur d’origine ne peut la contourner.
Une meilleure approche : sortir l’import de la requête HTTP
Plutôt que de repousser indéfiniment les timeouts, la solution la plus robuste consiste à ne jamais faire dépendre un traitement long d’une requête HTTP synchrone. WordPress fournit pour cela l’API Cron, qui permet de planifier un traitement en arrière-plan :
if ( ! wp_next_scheduled( 'import_produits_batch' ) ) {
wp_schedule_single_event( time() + 5, 'import_produits_batch' );
}
add_action( 'import_produits_batch', 'traiter_lot_suivant' );
Le navigateur reçoit alors une réponse immédiate confirmant la mise en file d’attente, pendant que le traitement réel se déroule par lots successifs, chacun assez court pour ne jamais approcher le moindre délai de proxy.
Prévention : documenter les délais de la chaîne
Le plus utile après un tel incident n’est pas seulement le correctif, mais la documentation de la chaîne complète des délais, couche par couche, dans le runbook technique du projet. La prochaine personne qui verra un 504 sur un traitement long n’aura pas à refaire cette enquête depuis zéro.
Un principe qui vaut sur tous nos projets : jamais de traitement de plus de dix secondes directement dans une requête HTTP synchrone. Au-delà, c’est un job en arrière-plan, point final.
En résumé
Un 504 Gateway Timeout qui survient toujours au même instant, indépendamment du volume traité, désigne presque toujours un délai de proxy amont plutôt qu’une limite PHP. Le vérifier avec WP-CLI en dehors du navigateur permet de trancher en quelques minutes, et de rediriger l’énergie de correction vers la bonne couche de l’infrastructure.