WordPress 503 Service indisponible : que vérifier quand le site est hors service

Cet article vous a aidé ?

Le 503 est le bruit qu’un site web fait quand il ne peut pas tenir ses promesses. Vos utilisateurs voient une page blanche, votre équipe marketing voit des revenus perdus, et vous voyez un ticket qui dit « site indisponible » sans aucun détail utile.

Ce guide explique comment couper à travers le bruit. Pas des recettes folklore du type « videz votre cache ». Des vérifications réelles, des commandes que vous pouvez lancer et des décisions à prendre pendant que le compteur d’incident tourne.

Ce que signifie vraiment un 503 (et ce qu’il ne signifie pas)

Un 503 « Service indisponible » n’est pas un seul bug. C’est une classe d’échecs où un composant du chemin de requête ne peut pas servir la demande pour le moment. L’expression clé est « pour le moment » : le système est suffisamment vivant pour répondre, mais assez malade pour refuser, expirer ou décharger la charge.

Dans l’écosystème WordPress, le 503 provient généralement de l’un de ces points d’étranglement :

  • Proxy/boîte d’entrée/CDN (Cloudflare, Fastly, ALB/ELB, Nginx) : l’origine est indisponible ou trop lente, checks de santé échouent, erreurs en amont.
  • Serveur web (Nginx/Apache) : incapacité à joindre l’upstream, trop de fichiers ouverts, limites de workers, saturation des files d’attente.
  • Runtime applicatif (PHP-FPM) : gestionnaire de processus au maximum, requêtes lentes, workers bloqués, kills OOM.
  • Base de données (MySQL/MariaDB) : connexions max atteintes, disque plein, requêtes longues, réplication en retard si les lectures sont séparées.
  • Stockage (disque local, NFS, EBS) : pics de latence, attente I/O, épuisement d’inodes, problèmes de permissions après déploiements.
  • Dépendances externes (SMTP, API paiement, recherche) : thème/plugin WordPress bloquant sur des appels distants.

Deux non-vérités importantes :

  • 503 n’est pas « WordPress est cassé ». WordPress peut très bien fonctionner ; c’est la plateforme autour qui peut s’écrouler.
  • 503 n’est pas « le CPU est élevé ». Un CPU haut peut en être la cause, mais des disques lents, un résolveur DNS bloqué ou un plugin isolé peuvent aussi en être responsables.

Une citation à garder au-dessus de l’écran pendant les incidents : idée paraphrasée de John Allspaw : le système vous raconte une histoire ; allez trouver la narration, pas un bouc émissaire.

Blague #1 : Un 503 est la façon dont votre serveur dit « je suis occupé » sans donner d’estimation — en gros le support technique, mais avec des en-têtes HTTP.

Mode opératoire de diagnostic rapide (premier/deuxième/troisième)

Quand le site est indisponible, vous n’avez pas besoin d’un audit profond d’emblée. Vous avez besoin d’un entonnoir qui vous mène au goulot en quelques minutes. Voici la séquence qui fonctionne en incidents réels.

Premier : confirmer où le 503 est généré (edge vs origine)

  1. Vérifier depuis l’extérieur : recevez-vous un 503 du CDN/load balancer ou de votre origine ?
  2. Vérifier depuis l’intérieur : faites un curl directement contre l’origine (ou le VIP du service) depuis une machine du même réseau.
  3. Décision : Si l’edge retourne 503 mais que l’origine est saine, concentrez-vous sur les checks de santé, les règles WAF, la connectivité origine, TLS ou les timeouts en amont. Si l’origine retourne aussi 503, creusez davantage.

Deuxième : décider si vous manquez de capacité ou si quelque chose est cassé

  1. Regarder charge, mémoire et disque sur l’origine : la machine est-elle en thrashing, en swap, avec de l’I/O wait, ou manque-t-elle d’espace ?
  2. Décision : Si vous êtes limité par les ressources, atténuez d’abord (scale out, redémarrage sûr, décharge de charge), puis enquêtez sur la cause racine après le rétablissement.

Troisième : suivre le chemin de la requête, étape par étape

  1. Logs du serveur web : les requêtes atteignent-elles Nginx/Apache, et quelles erreurs upstream apparaissent ?
  2. Statut PHP-FPM : les pools sont-ils saturés, des workers bloqués, les slow logs s’allument-ils ?
  3. Santé de la base : connexions, requêtes lentes, verrous, disque et pression du buffer pool.
  4. Décision : Une fois que vous trouvez le premier composant qui échoue (pas le dernier qui se plaint), vous avez trouvé le « bouton de commande » de l’incident.

Règle de rapidité : si vous ne pouvez pas expliquer le 503 au bout de 10 minutes, vous regardez probablement le mauvais niveau. Déplacez-vous d’un niveau vers le haut ou le bas de la chaîne.

Faits et contexte intéressants (rapide mais utile)

  • HTTP 503 a une intention « honnête » : il est conçu pour être temporaire et peut inclure un en-tête Retry-After pour les clients bien élevés.
  • 503 est couramment utilisé pour le mode maintenance car il indique aux moteurs de recherche « ne pas indexer comme une panne permanente », contrairement au 404.
  • Beaucoup de proxies émettent 503 pour des problèmes en amont même si l’origine aurait renvoyé 504 ou 500 — votre code d’erreur peut être une traduction, pas une vérité brute.
  • Nginx renvoie 502/504 pour beaucoup d’échecs upstream, mais certaines configurations ou load balancers intermédiaires peuvent les faire apparaître comme 503.
  • WordPress lui-même émet rarement un 503 brut ; c’est typiquement la couche web, PHP-FPM ou un chemin fatal d’un plugin qui fait échouer les checks de santé du serveur.
  • PHP-FPM est depuis longtemps le « levier de montée en charge » pour WordPress dans de nombreux stacks car il découple les workers PHP du modèle de processus du serveur web.
  • Le « thundering herd » n’est pas théorique : une expiration du cache à la seconde près sur de nombreux nœuds peut provoquer une ruée synchronisée, poussant PHP-FPM vers des 503.
  • Certaines plateformes WordPress managées renvoient intentionnellement 503 pour protéger l’infrastructure partagée sous forte charge, préférant une disponibilité partielle à un effondrement total.

Questions de triage qui réduisent le rayon d’impact

Posez celles-ci avant de commencer à redémarrer des services comme à la roulette.

  • Est-ce toutes les pages ou seulement certaines ? Si seul l’administration ou le checkout échoue, pensez sessions, verrous de base, ou APIs externes.
  • Est-ce toutes les régions ou une seule ? Si une seule région échoue, suspectez routage, DNS ou un problème de stockage zonal.
  • Quelque chose a-t-il changé ? Déploiements, mises à jour de plugins, modifications de thème, montée de version PHP, changements de règles WAF, rotation de certificats.
  • Est-ce lié à la charge ? Pic de trafic, vague de bots, ou un job cron qui tourne à l’heure pile et transforme votre base en soupe.
  • Est-ce intermittent ? Les 503 intermittents sentent la saturation : limites de workers, pools de connexions, ou I/O lente.

L’objectif est de choisir une hypothèse que l’on peut invalider rapidement. La réponse aux incidents est essentiellement de la science, mais avec plus de café et moins de subventions.

Tâches pratiques : commandes, sorties, décisions (12+)

Ci‑dessous des tâches pratiques à exécuter sur une origine Linux WordPress typique (Nginx + PHP-FPM + MySQL/MariaDB). Ajustez les noms de service pour votre distro. Chaque tâche inclut : commande, sortie d’exemple, ce que cela signifie et ce que vous faites ensuite.

Task 1: Verify the symptom from the outside (status code + headers)

cr0x@server:~$ curl -sS -o /dev/null -D - https://example.com | sed -n '1,20p'
HTTP/2 503
date: Thu, 26 Dec 2025 10:12:41 GMT
content-type: text/html; charset=UTF-8
server: cloudflare
cf-ray: 88c0a1b8f9c01234-AMS

Signification : La réponse est générée en edge (server: cloudflare). Vous n’êtes pas encore sûr si l’origine est en panne ou si l’edge ne peut pas l’atteindre.

Décision : Testez l’origine directement (Task 2). Si l’origine est saine, enquêtez sur la connectivité CDN/origine, firewall, TLS ou checks de santé.

Task 2: Curl the origin directly (bypass CDN)

cr0x@server:~$ curl -sS -o /dev/null -D - -H 'Host: example.com' http://127.0.0.1/ | sed -n '1,15p'
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx
Date: Thu, 26 Dec 2025 10:13:02 GMT
Content-Type: text/html
Content-Length: 190
Connection: keep-alive

Signification : L’origine renvoie elle‑même un 503 (nginx). Vous êtes maintenant dans la pile d’origine : Nginx, PHP-FPM, application, base de données, stockage.

Décision : Passez aux logs du serveur web et à la santé des upstreams (Tasks 6–8).

Task 3: Check basic host pressure (load, memory, swap)

cr0x@server:~$ uptime
 10:13:12 up 23 days,  4:01,  2 users,  load average: 18.42, 17.90, 16.55

Signification : La charge moyenne est très élevée. Cela peut indiquer saturation CPU, I/O wait, ou explosion de la file de processus runnable due à trop de processus.

Décision : Confirmez si la charge vient du CPU ou de l’I/O (Task 4) avant d’augmenter aveuglément les workers PHP (ce qui peut empirer la situation).

Task 4: Identify CPU vs I/O wait (vmstat)

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
16  4      0  32120  11244 622144    0    0   120  3400 2200 6100 15  8 20 57  0
18  3      0  29804  10980 615332    0    0    90  4100 2400 6500 12  7 18 63  0
20  5      0  28512  10820 612110    0    0   110  5200 2500 6900 10  6 14 70  0
15  2      0  31040  11100 620400    0    0    95  3800 2100 6000 14  7 22 57  0
17  4      0  29520  10920 614880    0    0   105  4600 2450 6700 11  6 16 67  0

Signification : Un wa élevé (I/O wait) indique que les CPU attendent principalement le disque/le stockage réseau. La colonne « b » (bloqué) est aussi élevée.

Décision : Enquêter sur la latence disque et la pression du système de fichiers (Tasks 5 et 14). Ne « corrigez » pas cela en ajoutant des enfants PHP-FPM ; vous créerez juste plus de processus bloqués.

Task 5: Check disk space and inode exhaustion

cr0x@server:~$ df -hT /
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  ext4   40G   39G  520M  99% /

Signification : Vous êtes quasiment à court d’espace disque. De nombreux services échouent de façon étrange quand ils ne peuvent plus écrire logs, fichiers temporaires ou sockets.

Décision : Libérez de l’espace immédiatement (rotation des logs, suppression de gros fichiers temporaires, déplacer des backups), puis retestez. Si ce sont les inodes, vérifiez la Task 5b :

cr0x@server:~$ df -i /
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/nvme0n1p2  2621440 2619900   1540  100% /

Signification : Épuisement des inodes : trop de petits fichiers (répertoires de cache, sessions, variantes d’images). WordPress avec un cache agressif peut causer cela.

Décision : Purgez les répertoires de cache et le stockage de sessions ; envisagez de déplacer les caches en tmpfs ou vers un stockage objet à plus long terme.

Task 6: Check Nginx error log for upstream clues

cr0x@server:~$ sudo tail -n 30 /var/log/nginx/error.log
2025/12/26 10:12:58 [error] 22114#22114: *98123 connect() to unix:/run/php/php8.2-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 203.0.113.10, server: example.com, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
2025/12/26 10:13:01 [error] 22114#22114: *98145 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 198.51.100.42, server: example.com, request: "GET /wp-admin/ HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"

Signification : Nginx ne peut parfois pas se connecter au socket PHP-FPM et expire d’autres fois. C’est typiquement une saturation PHP-FPM, des workers bloqués, ou un problème de backlog du socket.

Décision : Inspecter la santé du service PHP-FPM et le statut des pools (Tasks 7–9). Si PHP-FPM est arrêté, redémarrez-le ; s’il est en place mais saturé, trouvez le chemin lent.

Task 7: Check whether PHP-FPM is running and stable

cr0x@server:~$ systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-12-26 09:02:11 UTC; 1h 11min ago
       Docs: man:php-fpm8.2(8)
   Main PID: 1032 (php-fpm8.2)
     Status: "Processes active: 64, idle: 0, Requests: 92314, slow: 387, Traffic: 0.0req/sec"
      Tasks: 65 (limit: 18922)
     Memory: 2.4G
        CPU: 1h 03min

Signification : « idle: 0 » avec beaucoup de processus actifs suggère une saturation complète. Si votre pool a un max children à 64, vous avez atteint le plafond.

Décision : N’augmentez pas simplement le max children jusqu’à l’effondrement de la machine. Déterminez d’abord pourquoi les workers sont lents (Task 9) et si la base de données ou le stockage est le vrai goulot (Tasks 11–14).

Task 8: Check PHP-FPM socket and listen backlog

cr0x@server:~$ sudo ss -xlpn | grep php
u_str LISTEN 0      128    /run/php/php8.2-fpm.sock  22139            * 0 users:(("php-fpm8.2",pid=1032,fd=8))

Signification : Le backlog du socket est 128. Si vous voyez beaucoup de connexions en attente ou des erreurs comme « Resource temporarily unavailable », le backlog et la disponibilité des processus importent.

Décision : Si le backlog est trop petit pour vos pics de trafic, tunnez listen.backlog et le kernel somaxconn plus tard. Pour l’instant, trouvez pourquoi les workers ne se libèrent pas.

Task 9: Enable/inspect PHP-FPM slow log (find the slow code path)

cr0x@server:~$ sudo tail -n 30 /var/log/php8.2-fpm/slow.log
[26-Dec-2025 10:12:55]  [pool www] pid 11844
script_filename = /var/www/example.com/public/index.php
[0x00007f6b2c2f81f0] mysqli_query() /var/www/example.com/public/wp-includes/wp-db.php:2050
[0x00007f6b2c2f7f20] query() /var/www/example.com/public/wp-includes/wp-db.php:1941
[0x00007f6b2c2f7c50] get_results() /var/www/example.com/public/wp-includes/wp-db.php:2970
[0x00007f6b2c2f6a10] get_posts() /var/www/example.com/public/wp-includes/post.php:2543
[0x00007f6b2c2f51a0] WP_Query->get_posts() /var/www/example.com/public/wp-includes/class-wp-query.php:3604

Signification : Les workers sont bloqués dans des requêtes MySQL. Le 503 est un symptôme au niveau application d’un problème de base de données (ou d’une latence de stockage qui ralentit la base).

Décision : Orientez-vous vers la santé de la base et le comportement des requêtes (Tasks 11–13). Redémarrer PHP-FPM ne résoudra pas une base de données étouffée ; cela ne fait que réinitialiser brièvement la file.

Task 10: Verify WordPress cron isn’t stampeding

cr0x@server:~$ sudo tail -n 50 /var/log/syslog | grep -E 'wp-cron|cron' | tail -n 10
Dec 26 10:00:01 server CRON[21780]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)
Dec 26 10:00:02 server CRON[21795]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)
Dec 26 10:00:03 server CRON[21810]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)

Signification : Des invocations cron multiples successives peuvent s’empiler, surtout si un job est lent ou se chevauche. Le cron WordPress est notoire pour être « utile » au pire moment.

Décision : Désactivez temporairement le déclenchement WP cron via les requêtes web et migrez vers un cron système unique plus tard. Pendant l’incident, arrêtez la ruée et recontrôlez la charge.

Task 11: Check database max connections and thread pressure

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW GLOBAL VARIABLES LIKE 'max_connections';"
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 298   |
+-------------------+-------+
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 300   |
+-----------------+-------+

Signification : Vous êtes au plafond de connexions. Les nouvelles requêtes sont mises en file ou échouent ; les composants en amont peuvent produire des 503 selon leur gestion des timeouts.

Décision : Identifiez qui tient les connexions (Task 12) et pourquoi. Une mitigation temporaire peut être de redémarrer des clients runaway ou d’augmenter max connections si la mémoire le permet, mais corriger le comportement des requêtes est le vrai travail.

Task 12: Find long-running queries and locks

cr0x@server:~$ mysql -e "SHOW FULL PROCESSLIST;" | head -n 20
Id	User	Host	db	Command	Time	State	Info
421	wpuser	10.0.2.15:51244	wpdb	Query	87	Sending data	SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC LIMIT 0, 10
422	wpuser	10.0.2.15:51262	wpdb	Query	90	Locked	UPDATE wp_options SET option_value = '...' WHERE option_name = 'rewrite_rules'
430	wpuser	10.0.2.15:51410	wpdb	Sleep	220		NULL

Signification : Vous avez des requêtes bloquées (« Locked ») et des selects de longue durée. Des mises à jour de la table options (comme rewrite_rules) peuvent verrouiller et bloquer le site entier.

Décision : Si une requête particulière verrouille tout, il peut être nécessaire de la tuer chirurgicalement puis de désactiver le plugin/thème/action qui la provoque. Tuer des requêtes au hasard est la meilleure façon de créer des incidents SQL additionnels.

Task 13: Check MySQL slow query log signals (if enabled)

cr0x@server:~$ sudo tail -n 20 /var/log/mysql/slow.log
# Time: 2025-12-26T10:12:41.123456Z
# User@Host: wpuser[wpuser] @ 10.0.2.15 []
# Query_time: 5.882  Lock_time: 1.204 Rows_sent: 10  Rows_examined: 890221
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC LIMIT 0,10;

Signification : Le nombre de lignes examinées est énorme pour un petit ensemble de résultats. C’est un problème d’indexation, une requête sans limite ou un plugin qui fait une recherche de manière inefficace.

Décision : Appliquez des correctifs d’indexation et refactorez les requêtes après la récupération. Pendant l’incident, réduisez la charge (cache, rate-limit des bots, désactiver la fonctionnalité) et gardez la base respirer.

Task 14: Check storage latency and I/O wait at the device layer (iostat)

cr0x@server:~$ iostat -xz 1 3
Linux 6.1.0 (server) 	12/26/2025 	_x86_64_	(8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.31    0.00    6.22   58.44    0.00   23.03

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz  aqu-sz  %util
nvme0n1         42.00   1800.00     0.00   0.00   12.40    42.86  210.00  86000.00   120.00  36.36   95.20   409.52   20.10  99.80

Signification : Le write await est très élevé et le device est ~100% utilisé. Quand le stockage est saturé, les workers PHP se figent, la base se fige, et Nginx commence à renvoyer des timeouts/upstream/503.

Décision : Identifiez ce qui écrit (logs, backups, rafales de flush DB). Suspendez les I/O non essentielles (backups, cron, indexation) et envisagez de déplacer uploads/cache vers des volumes séparés plus tard.

Task 15: Check if the kernel is killing processes (OOM)

cr0x@server:~$ sudo dmesg -T | tail -n 20
[Thu Dec 26 10:11:33 2025] Out of memory: Killed process 11844 (php-fpm8.2) total-vm:2145120kB, anon-rss:612000kB, file-rss:0kB, shmem-rss:0kB, UID:33 pgtables:1920kB oom_score_adj:0

Signification : Des workers PHP-FPM sont tués par l’OOM. Cela peut se manifester par des 503 intermittents alors que la capacité chute et se rétablit.

Décision : Mitiger en réduisant le max children PHP-FPM, corriger les fuites mémoire (plugins), augmenter la mémoire prudemment et ajouter swap/mémoire uniquement avec intention.

Task 16: Check web server active connections and rate of requests

cr0x@server:~$ sudo ss -s
Total: 2345 (kernel 0)
TCP:   1988 (estab 612, closed 1201, orphaned 0, timewait 1103)

Transport Total     IP        IPv6
RAW	  0         0         0
UDP	  14        12        2
TCP	  787       735       52
INET	  801       747       54
FRAG	  0         0         0

Signification : Beaucoup de timewait et un grand nombre de connexions totales peuvent indiquer des rafales, des bots, un mauvais réglage des keepalive, ou le comportement du load balancer.

Décision : Si le trafic est malveillant, rate-limitez à l’edge ou via Nginx. Si c’est un trafic normal, assurez-vous que les limites de workers et de file descriptors ne sont pas trop basses.

Task 17: Confirm file descriptor limits (classic hidden 503 cause)

cr0x@server:~$ sudo cat /proc/$(pidof nginx | awk '{print $1}')/limits | grep -i "open files"
Max open files            1024                 1024                 files

Signification : 1024 fichiers ouverts pour Nginx est bas pour un site chargé (connexions, logs, fichiers temporaires). Quand vous l’atteignez, vous obtenez des erreurs upstream bizarres et des acceptations ratées.

Décision : Augmentez les limites via des overrides systemd et la config Nginx. Pendant un incident, réduire les connexions (rate-limit/bots) peut acheter du temps.

Task 18: Quickly test PHP execution without the full WordPress stack

cr0x@server:~$ printf '%s\n' '/dev/null
cr0x@server:~$ curl -sS http://127.0.0.1/health.php
ok

Signification : PHP-FPM peut exécuter un script trivial. Si les pages WordPress retournent 503 mais que ceci fonctionne, le runtime est vivant ; le problème est probablement le code WordPress (plugin/thème), la base ou le stockage.

Décision : Si le PHP trivial fonctionne, vérifiez la connectivité base de données et désactivez les plugins/thèmes récemment installés de manière contrôlée (voir la section checklist).

Modes de panne courants dans les stacks WordPress

1) Saturation du pool PHP-FPM (le plus courant, le moins compris)

Quand PHP-FPM est à court de workers inactifs, les requêtes font la queue sur le socket. Nginx attend. Finalement il abandonne et vous obtenez 503/504/502 selon le tuning et les composants en amont. L’utilisateur voit « Service indisponible », vous voyez une mare de workers en train d’exécuter quelque chose de lent.

Ce qui le cause :

  • Requêtes base de données lentes (index manquants, verrous de table, autoload d’options surchargé).
  • Stockage lent (uploads sur filesystem réseau, disque saturé).
  • Appels d’API externes dans le rendu de page (paiement/livraison, pixels marketing, polices distantes, vérifications de licence).
  • Trop de workers par rapport à la RAM disponible menant à de l’OOM, puis au thrash.

Stratégie de correction : Stabiliser d’abord : limiter la concurrence, redémarrer proprement si nécessaire, purger les caches prudemment. Puis trouver le chemin lent via les slow logs, le processlist DB et la traçabilité des requêtes.

2) Timeouts upstream du serveur web mal ajustés

Si vos timeouts upstream sont trop agressifs, des requêtes lentes légitimes sont coupées et ressemblent à des 503 pour les clients. Si les timeouts sont trop permissifs, vous construisez d’énormes files et amplifiez les pannes.

Règle d’opinion : les timeouts doivent refléter la réalité, pas l’espoir. Si les pages normales prennent 8 secondes, ne « corrigez » pas cela en mettant 120 secondes de timeout. Vous corrigez la page.

3) Plafond de connexions DB ou tempêtes de verrous

WordPress peut créer un nombre surprenant de requêtes concurrentes sous charge, surtout avec des plugins lourds. Quand la BD atteint max connections, les nouvelles requêtes PHP se bloquent ou échouent. Cela remonte comme « upstream timed out », « could not connect », ou un 503 pur des load balancers qui échouent les checks.

Les tempêtes de verrous viennent souvent de :

  • Plugins mettant fréquemment à jour wp_options.
  • Regénération de rewrite rules sur le trafic.
  • Plugins de cache effectuant des écritures sous charge.

4) Latence de stockage et désastres d’inodes

WordPress n’est pas que PHP et MySQL. C’est fichiers médias, caches, sessions et débris de plugins. Quand le stockage est lent, tout devient lent. Quand les inodes sont épuisés, tout devient cassé de façons créatives.

5) L’edge renvoie 503 parce que les checks de santé échouent

Votre origine peut servir des pages réelles mais échouer le endpoint de santé à cause de redirections, d’auth ou d’appels à des dépendances. Le load balancer marque alors la cible comme unhealthy et sert des 503 même si l’app est en grande partie vivante.

6) Meltdown d’un plugin/thème après une mise à jour

Un seul plugin peut ajouter des requêtes N+1, des appels distants ou un gros travail CPU sur chaque requête. Sous le trafic réel, c’est une forme lente de déni de service que vous vous êtes payée vous‑même.

Blague #2 : Le plugin garantissait d’« accélérer les performances ». Il l’a fait—jusqu’à ce qu’il augmente votre taux d’erreurs.

Trois mini-histoires du monde de l’entreprise (parce que ça arrive encore)

Mini-histoire 1 : L’incident causé par une mauvaise hypothèse

Ils avaient un site WordPress derrière un CDN et un load balancer managé. Pendant un lancement produit, des 503 sont apparus. L’équipe a supposé « l’origine est en panne » et a commencé à redémarrer PHP-FPM et à scaler des instances. Ça aidait pendant environ deux minutes à chaque fois. Les 503 revenaient comme une invitation récurrente au calendrier.

L’hypothèse erronée était subtile : ils traitaient le 503 comme une erreur applicative. Mais c’était le load balancer qui le renvoyait, parce que les checks de santé échouaient. Le chemin de santé était /, qui avait commencé à rediriger vers un chemin géo-spécifique après un changement marketing. Le load balancer ne suivait pas les redirections. Cibles unhealthy, 503 instantané.

Ça empirait car les redémarrages changeaient le timing et faisaient passer les checks de santé de façon intermittente. Ça créait une illusion de correctifs partiels, entraînant d’autres redémarrages, ce qui empirait la stabilité perçue. Tout le monde avait des graphiques. Personne n’avait le bon graphique.

La correction fut ennuyeuse : un endpoint dédié /healthz renvoyant un 200 simple, servi par Nginx sans PHP. Les checks se stabilisèrent immédiatement. Ensuite, l’équipe put voir le vrai problème : le trafic était élevé, mais la pile tenait une fois autorisée à recevoir des requêtes.

Mini-histoire 2 : L’optimisation qui a mal tourné

Une autre entreprise a voulu « accélérer WordPress » en augmentant fortement pm.max_children de PHP-FPM et en baissant les timeouts Nginx pour garder la réactivité. En staging ça semblait rapide. En production, la machine est devenue un radiateur avec un problème disque.

L’augmentation du nombre de workers a multiplié les requêtes concurrentes vers la DB. La BD a commencé à flusher constamment des pages sales. L’utilisation du disque a plafonné. L’I/O wait a grimpé. Les workers PHP se sont accumulés en attente de la DB, et les timeouts Nginx ont commencé à les couper. L’utilisateur a vu des 503 ; l’équipe a vu « mais nous avons augmenté la capacité ».

Ils avaient optimisé la capacité sur le papier, en ignorant le goulot partagé : l’I/O de la base sur stockage. Plus de concurrence n’a pas signifié plus de complétions. Ça a signifié plus d’attente.

Le plan de récupération fut de réduire intentionnellement la concurrence : baisser les enfants PHP-FPM pour correspondre à la capacité DB, étendre juste assez les timeouts amont pour éviter des retries massifs, et rate-limiter les endpoints coûteux. Après l’incendie, ils ont ajouté un vrai cache et corrigé les pires requêtes. L’« optimisation » est devenue une leçon sur les goulots.

Mini-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la journée

Un média exploitait WordPress sous un trafic élevé régulier. Leur arme secrète n’était pas un maillage de services sophistiqué. C’était la discipline : un endpoint de health check qui ne touche pas PHP, rotation régulière des logs, alertes de capacité sur disque et inodes, et un runbook d’incident standard que tout le monde utilisait réellement.

Un après-midi, le taux de 503 a augmenté. L’on-call a suivi le runbook : confirmer edge vs origine, vérifier le disque, vérifier PHP-FPM, vérifier les connexions DB. L’usage disque était correct, mais les inodes étaient presque épuisés. Un plugin de cache avait commencé à générer un énorme nombre de petits fichiers après un changement de config. PHP ne pouvait plus écrire les sessions correctement, et le site a commencé à lancer des erreurs et des timeouts.

Parce qu’ils avaient des alertes inodes, ils l’ont attrapé avant la panne totale. Ils ont purgé le répertoire de cache, appliqué une limite à la génération de fichiers de cache, et déplacé le cache vers Redis plus tard. Les utilisateurs ont vu un clignotement, pas un titre.

Cela n’était pas glamour. C’était correct. La correction ennuyeuse est la façon de gagner les outages sans devenir une histoire sur les réseaux sociaux.

Erreurs courantes : symptôme → cause racine → correction

Cette section empêche le modèle « on l’a redémarré six fois et maintenant c’est pire ».

503 seulement au CDN, l’origine a l’air saine

  • Symptôme : En‑têtes edge montrent CDN/load balancer ; curl de l’origine retourne 200.
  • Cause racine : Chemin de check de santé défaillant, IP origine bloquée, mismatch TLS, règle WAF, ou rate limiting de l’origine envers l’edge.
  • Correction : Utilisez un /healthz dédié qui renvoie 200 sans auth/redirects ; confirmez que le firewall autorise les IPs de l’edge ; vérifiez le certificat et le SNI ; consultez les logs de l’edge.

Pics de 503 lors de rafales de trafic, puis récupération

  • Symptôme : 503 intermittents, erreurs upstream timeout dans Nginx.
  • Cause racine : max children PHP-FPM atteint ; limite de connexions DB atteinte ; stampede de cache.
  • Correction : Ajoutez du caching qui évite les stampedes, tunez PHP-FPM pour correspondre CPU/RAM et capacité DB, rate-limitez les chemins de bots, et assurez-vous qu’OPcache est correctement configuré.

503 après une mise à jour de plugin/thème

  • Symptôme : L’interruption commence juste après la mise à jour ; l’administration peut être inaccessible ; les slow logs montrent des chemins PHP spécifiques.
  • Cause racine : Plugin causant des erreurs fatales, des explosions mémoire, ou des écritures DB lourdes ; incompatibilité avec la version PHP.
  • Correction : Désactivez le plugin en renommant son répertoire ou utilisez WP-CLI ; rollback ; verrouillez les versions ; introduisez staging et déploiements canaris.

503 corrélés à « Disque 100% » ou iowait élevé

  • Symptôme : iowait élevé, blocages MySQL, workers PHP bloqués.
  • Cause racine : Job de backup, inondation de logs, rafale de flush DB, stockage réseau lent, épuisement d’inodes.
  • Correction : Arrêtez/limitez les I/O bruyants ; déplacez les gros writers hors du volume root ; tunez le comportement de flush DB ; séparez uploads/cache ; surveillez la latence, pas seulement le débit.

Redémarrer PHP-FPM « corrige » brièvement

  • Symptôme : Amélioration immédiate, puis rechute rapide.
  • Cause racine : Réinitialisation de la file ; le goulot sous-jacent reste (DB, stockage, API externe) ; ou fuite mémoire qui se reconstruit rapidement.
  • Correction : Utilisez la fenêtre de récupération brève pour collecter des preuves : slow logs, processlist, top des coupables, et rate-limit. Ensuite, traitez la cause racine.

Seul wp-admin renvoie 503

  • Symptôme : La page d’accueil fonctionne parfois, l’administration échoue constamment.
  • Cause racine : Les pages à privilèges déclenchent une logique plugin plus lourde, des requêtes non mises en cache, ou des écritures de session ; peut aussi indiquer une lenteur du fournisseur d’auth.
  • Correction : Désactivez les plugins qui hookent l’administration ; vérifiez le stockage des sessions ; testez un endpoint PHP minimal ; enquêtez sur les appels d’auth externes.

Listes de vérification / plan étape par étape

Checklist A: 10 minutes de triage pour restaurer le service

  1. Localisez l’origine du 503 : edge vs origine (curl des headers ; accès direct à l’origine).
  2. Vérifiez la santé hôte : charge, mémoire, swap, espace disque, inodes.
  3. Consultez les logs Nginx/Apache : erreurs de connexion upstream, timeouts, « too many open files ».
  4. Vérifiez le statut PHP-FPM : en cours, max children atteint, activité slow log.
  5. Vérifiez la saturation DB : threads connected, max connections, processlist locks.
  6. Mitigez :
    • Rate-limitez les chemins abusifs/bots à l’edge ou Nginx.
    • Purgez ou réchauffez les caches critiques si c’est sûr.
    • Arrêtez les jobs background lourds (backups, imports, cron storms).
    • Rechargez/restart des services proprement seulement si vous comprenez ce que vous réinitialisez.
  7. Vérifiez le rétablissement : curl depuis l’origine et de l’extérieur, testez 2–3 pages clés, surveillez la baisse du taux d’erreurs.

Checklist B: Désactivation sûre d’un plugin quand wp-admin est HS

Si vous suspectez fortement un plugin et que vous ne pouvez pas accéder à l’admin, faites‑le depuis le système de fichiers. Méthode brutale mais efficace.

  1. Identifiez le(s) plugin(s) mis à jour récemment (par logs de déploiement ou mtime des fichiers).
  2. Désactivez en renommant le répertoire (WordPress l’ignorera).
  3. Retestez le endpoint de santé et la page d’accueil.
  4. Si ça revient, laissez le plugin désactivé et planifiez une réactivation contrôlée avec profilage.
cr0x@server:~$ cd /var/www/example.com/public/wp-content/plugins
cr0x@server:~$ sudo mv suspicious-plugin suspicious-plugin.disabled
cr0x@server:~$ curl -sS -o /dev/null -w "%{http_code}\n" -H 'Host: example.com' http://127.0.0.1/
200

Signification : Si le statut retourne 200 après désactivation, vous avez isolé la cause sur ce plugin ou quelque chose qu’il a déclenché.

Décision : Laissez‑le désactivé ; informez les parties prenantes ; capturez les logs et conservez une copie de la version du plugin pour analyse ultérieure.

Checklist C: Redémarrage gracieux des services sans empirer

Les redémarrages sont des outils, pas des prières. Utilisez‑les quand le composant est véritablement bloqué, pas comme substitut du diagnostic.

cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
cr0x@server:~$ sudo systemctl reload nginx
cr0x@server:~$ sudo systemctl restart php8.2-fpm

Signification : Rechargez Nginx d’abord (peu coûteux et faible risque) après vérification de config. Redémarrez PHP-FPM seulement si les workers sont bloqués/OOM et que vous devez dégager la congestion.

Décision : Si le redémarrage de PHP-FPM restaure le service mais que la rechute est rapide, arrêtez de redémarrer et passez à la collecte d’éléments de preuve du « chemin lent ».

Checklist D: Stabilisation après récupération (même jour)

  1. Gardez les rate limits jusqu’à confirmation de stabilité sous charge normale.
  2. Capturez les artefacts : requêtes lentes majeures, extraits des slow logs PHP-FPM, erreurs upstream Nginx, échantillons de processlist DB.
  3. Rédigez une timeline d’incident courte : ce qui a changé, quand ça a commencé, quelles mitigations ont marché.
  4. Transformez le point de douleur principal en garde‑fou permanent (alerte, dashboard, test automatisé).

FAQ

1) Un 503 WordPress est-il toujours un problème serveur ?

Non. C’est souvent le serveur qui réagit à un comportement applicatif : un plugin qui crée des requêtes coûteuses, un thème qui appelle des APIs externes, ou des jobs cron qui s’accumulent. Le serveur n’est que le messager.

2) Pourquoi je vois parfois 503 et parfois 504 ?

Différentes couches traduisent les échecs différemment. Un load balancer peut appeler un timeout upstream un 503, tandis que Nginx émettra 504. Concentrez‑vous sur l’endroit d’origine de l’échec, pas le code exact.

3) Dois‑je augmenter pm.max_children de PHP-FPM pour corriger un 503 ?

Uniquement si vous avez confirmé des ressources CPU/RAM libres et que la base/stockage peut supporter plus de concurrence. Sinon vous amplifiez le goulot et risquez des kills OOM et une latence pire.

4) Comment savoir si la base de données est le goulot ?

Les slow logs PHP-FPM montrant mysqli_query(), Threads_connected proche du max, des requêtes longues dans le processlist et un iowait élevé sur l’hôte DB sont des signaux forts.

5) Un CDN peut‑il causer un 503 alors que mon origine est OK ?

Oui. Échecs de checks de santé, accès origine bloqué, mismatch TLS/SNI, ou rate limiting peuvent faire qu’un edge renvoie 503. Testez toujours l’origine directement avec l’en‑tête Host correct.

6) Quelle est la façon la plus rapide d’isoler un mauvais plugin ?

Désactivez‑le sans passer par wp-admin : renommez le répertoire du plugin et retestez. Pour une approche plus chirurgicale, désactivez les plugins un par un en commençant par les plus récemment modifiés.

7) Pourquoi redémarrer « règle » temporairement ?

Parce que vous videz les files et tuez les workers bloqués, ce qui restaure brièvement la capacité. Si la dépendance lente subsiste, vous ne faites que remettre l’horloge à zéro.

8) Un 503 peut‑il être causé par des permissions de fichiers ?

Indirectement. Si WordPress ne peut pas écrire dans les répertoires uploads/cache/sessions, les requêtes peuvent bloquer ou échouer, entraînant des pannes upstream. Vérifiez les logs Nginx/PHP pour des erreurs de permission et la santé du système de fichiers.

9) Quel endpoint de health check utiliser pour les load balancers ?

Un endpoint statique servi par le serveur web (pas PHP), renvoyant 200 avec un travail minimal. Si vous avez besoin de checks plus profonds, créez un second endpoint pour la surveillance interne, pas pour la régulation du trafic.

10) Comment prévenir les 503 à long terme ?

Instrumentez les goulots (saturation PHP-FPM, connexions DB, latence disque), contrôlez la concurrence, cachez les bonnes choses, et traitez les mises à jour de plugins comme des déploiements — étagés et réversibles.

Conclusion : étapes suivantes après restauration

Une fois le site de nouveau servi, ne « clôturez pas l’incident » et partez. Le système vient de vous apprendre où il casse. Transformez cette leçon en valeur.

  1. Transformez la cause racine en garde‑fou : alertes sur inodes/latence disque, saturation PHP-FPM, marge de connexions DB et vérification des checks de santé.
  2. Corrigez le chemin lent : indexez les pires requêtes, retirez ou remplacez les comportements plugins les plus lourds, et arrêtez d’effectuer des appels distants dans le chemin de rendu critique.
  3. Dimensionnez correctement la concurrence : réglez les enfants PHP-FPM selon ce que la base et le stockage peuvent réellement soutenir, pas selon ce qui semble rassurant.
  4. Rendez les pannes moins coûteuses : ajoutez un vrai /healthz, mettez en place du caching avec protection contre les stampedes, et implémentez du rate limiting pour les endpoints abusifs.
  5. Rédigez le runbook que vous auriez voulu avoir : les commandes exactes que vous avez lancées, les logs importants, et les notes « ne pas refaire ». Au prochain incident vous serez fatigué et moins brillant — le runbook vous aidera.

Si vous faites ces cinq choses, le prochain 503 ne sera pas un mystère. Ce sera un mode d’échec connu avec une réponse courte, un peu exaspérée, mais efficace.

← Précédent
Proxmox vzdump backup failed : 10 causes réelles et comment vérifier dans l’ordre
Suivant →
Échec de la migration à chaud Proxmox : que vérifier pour le réseau, les flags CPU et le stockage

Laisser un commentaire