WordPress « Indisponible temporairement pour maintenance programmée » : pourquoi ça reste bloqué et comment le réparer

Cet article vous a aidé ?

Vous appuyez sur Actualiser. La bannière est toujours là. Votre page d’accueil est indisponible, votre responsable demande si « l’internet est cassé », et WordPress vous assure gaiement qu’il est « indisponible temporairement ».

Ce message est censé durer quelques secondes. Quand il persiste, ce n’est presque jamais mystérieux. C’est un simple fichier de verrouillage, une mise à jour ratée, ou un problème de permissions / stockage qui se déguise. Traiter cela comme un incident : vérifier l’impact, identifier le mécanisme bloquant, restaurer le service, puis corriger les conditions qui ont provoqué le problème.

Ce que signifie réellement le message de maintenance

Le mode maintenance de WordPress n’est pas un « mode » au sens moderne de feature-flag. C’est un verrou basé sur un fichier.
Pendant une mise à jour (core, plugin, thème, traductions), WordPress crée un fichier nommé .maintenance à la racine du site (même répertoire que wp-config.php).
Tant que ce fichier existe et paraît « récent », WordPress court-circuite le rendu normal des pages et retourne le message de maintenance.

Le mécanisme est volontairement basique. Mettre à jour du code sur le disque pendant que des requêtes exécutent du PHP est un champ de mines. Le fichier de verrouillage est la façon dont WordPress dit :
« Laissez-moi faire. Je remplace des pièces. »

Le mode maintenance est censé se lever automatiquement à la fin d’une mise à jour réussie. Lorsqu’il ne le fait pas, le fichier de verrouillage reste, ou WordPress continue de penser qu’une mise à niveau est en cours parce que quelque chose est bloqué : un paquet partiellement extrait, un problème de permissions, un disque plein, une réponse mise en cache, ou un processus PHP qui est mort en plein traitement.

Le message dit honnêtement une chose : cela arrive réellement pendant une maintenance programmée. Le mensonge, c’est « temporairement ».

Comment WordPress décide d’afficher le message

À un niveau élevé, WordPress fait ceci :

  • Crée .maintenance avec un timestamp.
  • Exécute le processus de mise à jour (téléchargement, décompression, copie, éventuellement mises à jour de la base).
  • Supprime .maintenance une fois terminé.

Si le processus de mise à jour est interrompu—timeout HTTP, erreur fatale PHP, échec d’écriture sur le système de fichiers, worker tué, crash, ou une personne qui clique sur « Tout mettre à jour » puis ferme l’onglet en cours de requête—l’étape de nettoyage peut ne jamais s’exécuter.

Blague n°1 : Le mode maintenance de WordPress, c’est comme un panneau « Ne pas déranger »—idéale jusqu’à ce que le service de nettoyage ne revienne jamais et que vous commenciez à vivre avec les serviettes d’hier.

Faits intéressants et un peu d’histoire (parce que ça compte)

Si vous exploitez WordPress en production, il est utile de connaître les hypothèses intégrées à ses mécanismes de mise à jour et de verrouillage. Voici des faits concrets qui expliquent pourquoi ce problème continue d’apparaître en 2025 :

  1. Le verrou est un fichier, pas un drapeau en base de données. Ce choix remonte à la simplicité des débuts de WordPress : on supposait que les écritures sur le système de fichiers étaient moins coûteuses que des changements de schéma et sûres sur l’hébergement mutualisé.
  2. Les mises à jour automatiques en arrière-plan sont arrivées avec WordPress 3.7 (2013). Avant cela, la plupart des mises à jour étaient manuelles et interactives, donc les échecs étaient détectés plus rapidement—par des humains irrités.
  3. Le message de maintenance est volontairement générique. Il évite d’exposer des détails internes aux utilisateurs non authentifiés, ce qui est une bonne pratique de sécurité mais mauvais pour l’ergonomie des opérateurs.
  4. Les mises à jour du core utilisent une stratégie « copier puis échanger ». WordPress essaie de réduire les états de mise à jour partiels, mais les plugins/thèmes restent vulnérables à des répertoires à moitié écrits si le processus est interrompu.
  5. La logique des identifiants de fichier existe car de nombreux sites ne peuvent pas écrire dans leurs propres répertoires. Cet héritage d’un hébergement FTP partagé influence toujours la façon dont échouent les mises à jour (demandes d’identifiants, impossibilité d’écrire, échecs partiels silencieux).
  6. Les mises à jour de traductions sont un flux d’updates à part. Elles peuvent déclencher le mode maintenance aussi, même quand vous jurez « on n’a rien changé ».
  7. Les caches d’objets et caches de pages peuvent survivre au verrou. Vous pouvez supprimer .maintenance et continuer à afficher la bannière si un cache en amont a décidé que ce message est « du contenu ».
  8. Les déploiements blue/green ont rendu cela plus rare—jusqu’à ce que des gens recommencent à mettre à jour des nœuds en production. Dans les environnements conteneurisés, mettre à jour le disque dans un conteneur en cours d’exécution équivaut désormais à éditer la production avec vim.
  9. Certaines plateformes d’hébergement implémentent leurs propres basculements de maintenance. Les plateformes WordPress gérées peuvent afficher le même message via des règles proxy, pas via WordPress lui‑même.

Plan de diagnostic rapide (premier/deuxième/troisième)

Vous voulez le chemin le plus court vers « site de nouveau disponible » sans créer un incident plus intéressant. Voici l’ordre qui fonctionne quand vous êtes d’astreinte et que votre café est encore en train de chauffer.

Premier : confirmer si c’est WordPress ou l’edge qui vous ment

  • Contournez les caches et testez l’origine directement (ou au moins avec des en‑têtes qui cassent le cache).
  • Si la bannière persiste uniquement via le CDN/WAF mais pas à l’origine, c’est un incident de cache, pas un incident WordPress.

Deuxième : vérifier l’existence de .maintenance et son horodatage

  • Si .maintenance existe et est ancien, supprimez‑le puis retestez.
  • S’il est récent et que des mises à jour sont effectivement en cours, ne retirez pas le fichier à l’aveugle—vérifiez que le processus de mise à jour n’est pas encore en train de copier des fichiers.

Troisième : trouver la mise à jour qui a échoué et pourquoi

  • Consultez les journaux d’erreurs PHP-FPM/Apache/Nginx pour des fatales/timeouts pendant la mise à jour.
  • Vérifiez l’espace disque et l’épuisement des inodes (oui, les inodes gâchent encore des journées).
  • Vérifiez les permissions/ownership : l’utilisateur PHP peut‑il écrire dans wp-content et (pour le core) à la racine de WordPress ?
  • Vérifiez la présence d’artéfacts coincés dans wp-content/upgrade.

Pourquoi ça reste bloqué : les véritables modes de défaillance

1) Le fichier .maintenance n’a jamais été supprimé

Le cas le plus fréquent. Une requête a expiré, un worker PHP est mort, quelqu’un a quitté la page, ou le serveur web a redémarré en plein milieu d’une mise à jour.
WordPress n’a pas de balayeur en arrière‑plan qui nettoie fiablement après une interruption catastrophique.

Si vous supprimez le fichier et que tout charge, vous n’avez pas « réparé » la mise à jour—vous avez supprimé le verrou. Parfois c’est suffisant. Parfois vous venez seulement de débloquer les utilisateurs tout en laissant un plugin à moitié mis à jour qui plantera plus tard.

2) Mise à jour partielle : répertoire plugin/thème dans un état cassé

Les mises à jour peuvent laisser derrière :

  • Un dossier de plugin sans fichiers critiques (autoloaders, fichier principal du plugin).
  • Une nouvelle version extraite dans un répertoire temporaire mais non déplacée en place.
  • Un mélange d’anciens et de nouveaux fichiers à cause d’un échec de permissions en plein copy.

Supprimer .maintenance peut simplement révéler le vrai problème : erreurs fatales, écrans blancs, ou boucles de connexion admin.

3) Mismatch de permissions/ownership du système de fichiers

Les mises à jour WordPress nécessitent un accès en écriture. Sur beaucoup de serveurs, le code appartient à un utilisateur de déploiement (ou root), mais PHP s’exécute en tant que www-data (ou équivalent).
Les mises à jour échouent alors à mi‑parcours : le zip téléchargé existe, l’extraction échoue, le nettoyage ne s’exécute pas, .maintenance reste.

4) Problèmes de stockage : disque plein, inodes pleins, I/O lente, ou aléas de stockage réseau

En tant qu’ingénieur stockage : c’est là que la partie « temporairement » meurt.
Les mises à jour sollicitent beaucoup le disque : téléchargement, décompression (beaucoup de petits fichiers), renommage, suppression.
Si votre disque est plein, ou votre table d’inodes saturée, ou votre backend NFS/EFS/SMB a un moment de faiblesse, la mise à jour peut bloquer ou échouer à une étape aléatoire.

5) Les couches de cache continuent de servir la bannière après correction

Les CDN, reverse proxies et plugins de cache WordPress peuvent mettre en cache la réponse de maintenance comme si c’était une page valide.
L’origine est saine, mais l’edge continue de rejouer la mauvaise nouvelle.

6) Mises à jour concurrentes ou ruée sur « Tout mettre à jour »

Plusieurs administrateurs qui cliquent sur les boutons de mise à jour en même temps sont un générateur de chaos sous‑estimé.
Même avec un verrou de maintenance, vous pouvez avoir des tentatives qui se chevauchent et laissent des répertoires temporaires et des états incohérents.

7) « Mode maintenance » du fournisseur géré ou mises à jour de la plateforme

Certaines plateformes affichent le même message pendant qu’elles font un snapshot, migrent ou patchent. Dans ce cas, supprimer .maintenance n’aidera pas parce que WordPress n’est pas celui qui l’émet.

Tâches pratiques avec commandes : diagnostiquer, décider, réparer

Ci‑dessous des tâches réelles que vous pouvez exécuter sur un hôte Linux typique. Chaque tâche inclut : la commande, ce que signifie la sortie, et la décision que vous prenez.
Ajustez les chemins à votre docroot. Supposez que la racine WordPress soit /var/www/example.com/public.

Task 1: Confirm you’re seeing the origin, not a cached edge response

cr0x@server:~$ curl -sS -D- -o /dev/null -H 'Cache-Control: no-cache' https://example.com/ | sed -n '1,20p'
HTTP/2 503
date: Sat, 27 Dec 2025 12:01:11 GMT
content-type: text/html; charset=UTF-8
cache-control: no-cache, must-revalidate, max-age=0
server: nginx

Ce que cela signifie : HTTP 503 est cohérent avec le mode maintenance de WordPress. Si vous aviez vu des en‑têtes comme x-cache: HIT ou des en‑têtes spécifiques au CDN, vous suspecteriez le cache.

Décision : Si la réponse est 503 à l’origine aussi, passez aux vérifications côté serveur. Si l’origine renvoie 200 mais l’edge 503, purgez/bannez le cache et révisez les règles CDN.

Task 2: Check if .maintenance exists (and where)

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && ls -la .maintenance || echo "no .maintenance"'
-rw-r--r-- 1 www-data www-data 55 Dec 27 11:43 .maintenance

Ce que cela signifie : Le fichier existe et est lisible. Sa présence seule peut déclencher la bannière.

Décision : Vérifiez ensuite la fraîcheur de l’horodatage. S’il est ancien, vous pouvez généralement le supprimer. S’il est récent, confirmez qu’une mise à jour est réellement en cours.

Task 3: Inspect the contents of .maintenance

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && cat .maintenance'
<?php $upgrading = 1766835803; ?>

Ce que cela signifie : Il contient un timestamp UNIX. WordPress s’en sert pour décider si le verrou est « périmé ».

Décision : Convertissez‑le en heure humaine et comparez avec maintenant.

Task 4: Convert the upgrade timestamp and judge staleness

cr0x@server:~$ date -d @1766835803
Sat Dec 27 11:43:23 UTC 2025

Ce que cela signifie : Vous savez maintenant quand la maintenance a commencé.

Décision : Si c’était il y a 30+ minutes et qu’aucune mise à jour n’est en cours, considérez‑le comme bloqué et supprimez le fichier après avoir vérifié les logs pour des échecs.

Task 5: Check whether an update process is actively running (PHP-FPM workers, unzip, wp-cli)

cr0x@server:~$ ps aux | egrep 'wp-cli|wordpress|unzip|php.*(update|upgrade)' | grep -v egrep
www-data  21904  0.2  1.1 312000 46000 ?        S    11:42   0:02 php-fpm: pool www

Ce que cela signifie : Rien d’évident n’est en cours à part les workers PHP normaux.

Décision : On peut supposer que la mise à jour n’est pas en cours. Passez au nettoyage : supprimez le verrou puis validez l’intégrité.

Task 6: Remove .maintenance safely and retest

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && rm -v .maintenance'
removed '.maintenance'

Ce que cela signifie : Le verrou est parti.

Décision : Retestez immédiatement le site et l’admin. S’il charge, vous devez quand même vérifier que les mises à jour n’ont pas laissé le code à moitié cassé.

Task 7: Check for the upgrade working directory that signals interrupted upgrades

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && ls -la wp-content | sed -n "1,60p"'
total 64
drwxr-xr-x  9 www-data www-data 4096 Dec 27 11:42 .
drwxr-xr-x  5 www-data www-data 4096 Dec 27 11:40 ..
drwxr-xr-x  2 www-data www-data 4096 Dec 27 11:42 upgrade
drwxr-xr-x 36 www-data www-data 4096 Dec 27 11:10 plugins
drwxr-xr-x  8 www-data www-data 4096 Dec 27 10:55 themes

Ce que cela signifie : Le répertoire upgrade existe. C’est normal pendant les mises à jour ; c’est suspect s’il reste plein de débris.

Décision : Inspectez‑le. S’il contient des extraits partiels datant de plusieurs heures, nettoyez après avoir confirmé qu’aucune mise à jour n’est en cours.

Task 8: Inspect wp-content/upgrade contents

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && find wp-content/upgrade -maxdepth 2 -type f | head'
wp-content/upgrade/temp-backup/plugin-akismet.1766835740.zip
wp-content/upgrade/akismet/akismet.php

Ce que cela signifie : Vous avez des artéfacts laissés. Pas toujours nuisible, mais signe que le chemin de mise à jour ne s’est pas terminé proprement.

Décision : Si le site est stable, vous pouvez supprimer le contenu temporaire périmé de upgrade pour éviter des collisions futures et récupérer de l’espace.

Task 9: Check disk space (updates fail when you’re out of space)

cr0x@server:~$ df -h /var/www/example.com/public
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        40G   39G  300M  99% /

Ce que cela signifie : 99% d’utilisation. Les mises à jour ont besoin de marge pour les zips et la décompression. 300MB, c’est « une mise à jour de plugin près de la honte ».

Décision : Libérez de l’espace avant de relancer les mises à jour. Sinon vous répéterez l’incident.

Task 10: Check inode exhaustion (the silent killer of “lots of small files” operations)

cr0x@server:~$ df -i /var/www/example.com/public
Filesystem       Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1      2621440 2621200     240  100% /

Ce que cela signifie : Vous avez pratiquement zéro inode. Décompresser des mises à jour WordPress crée des milliers de fichiers ; l’épuisement des inodes rend l’écriture impossible même s’il reste de l’espace.

Décision : Trouvez et supprimez les éléments qui consomment beaucoup d’inodes (caches, anciennes sauvegardes, fichiers temporaires). Puis relancez les mises à jour.

Task 11: Check file ownership and permissions in the WordPress root

cr0x@server:~$ sudo bash -lc 'cd /var/www/example.com/public && stat -c "%U:%G %a %n" wp-config.php wp-content wp-admin | sed -n "1,10p"'
root:root 640 wp-config.php
root:root 755 wp-content
root:root 755 wp-admin

Ce que cela signifie : Tout appartient à root. Si PHP s’exécute en tant que www-data, WordPress ne peut pas écrire les mises à jour à moins d’avoir configuré des méthodes/ACLs de fichier.

Décision : Choisissez votre modèle opérationnel : soit (a) déployer de manière immuable et faire les mises à jour via CI/CD, soit (b) permettre à WordPress d’écrire en corrigeant ownership/ACLs. Ne mélangez pas les deux à moitié.

Task 12: Verify the PHP runtime user and whether it can write

cr0x@server:~$ ps -o user,group,comm -C php-fpm8.2 2>/dev/null | head
USER     GROUP    COMMAND
root     root     php-fpm8.2
www-data www-data php-fpm8.2

Ce que cela signifie : Les workers s’exécutent en tant que www-data.

Décision : Assurez‑vous que www-data a les permissions d’écriture là où les mises à jour ont lieu (souvent wp-content et parfois la racine pour les mises à jour du core). Si vous ne pouvez pas permettre cela, cessez les mises à jour in‑place.

Task 13: Run WP-CLI to check core integrity and pending updates

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && wp core verify-checksums'
Success: WordPress installation verifies against checksums.

Ce que cela signifie : Les fichiers core correspondent aux checksums attendus pour votre version. Bon signe que le core n’a pas été partiellement mis à jour.

Décision : Si cela échoue, prévoyez de réinstaller les fichiers core (sans toucher à wp-content) ou redéployez depuis un artefact connu sain.

Task 14: Identify what was updating when it got stuck

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && wp plugin list --update=available'
+-------------------+----------+-----------+---------+
| name              | status   | update    | version |
+-------------------+----------+-----------+---------+
| akismet           | active   | available | 5.3     |
| woocommerce       | active   | available | 8.4.0   |
+-------------------+----------+-----------+---------+

Ce que cela signifie : Des mises à jour sont disponibles ; le blocage a probablement eu lieu pendant l’une d’elles (ou pendant des mises à jour core/thème).

Décision : Ne cliquez pas sur « tout mettre à jour » à nouveau. Mettez à jour un composant à la fois après avoir stabilisé le disque/permissions, en surveillant les logs.

Task 15: Check recent PHP errors that often coincide with failed upgrades

cr0x@server:~$ sudo tail -n 60 /var/log/php8.2-fpm.log
[27-Dec-2025 11:42:19] WARNING: [pool www] child 22001 said into stderr: "PHP Fatal error:  Uncaught Error: Class 'Automattic\WooCommerce\Internal\DependencyManagement\Container' not found in /var/www/example.com/public/wp-content/plugins/woocommerce/woocommerce.php:45"
[27-Dec-2025 11:42:19] WARNING: [pool www] child 22001 said into stderr: "PHP Stack trace: #0 {main} thrown in /var/www/example.com/public/wp-content/plugins/woocommerce/woocommerce.php on line 45"

Ce que cela signifie : Un plugin est dans un état cassé (classe manquante). C’est un classique de mise à jour partielle : certains fichiers ont été déplacés, d’autres non.

Décision : Restaurez ce répertoire de plugin depuis une version connue bonne (backup/artefact), ou réinstallez via WP-CLI. Ne supprimez pas des fichiers au hasard.

Task 16: Reinstall a broken plugin cleanly (without guessing)

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && wp plugin deactivate woocommerce && wp plugin install woocommerce --force --activate'
Plugin 'woocommerce' deactivated.
Installing WooCommerce (9.1.0)
Downloading installation package from https://downloads.wordpress.org/plugin/woocommerce.9.1.0.zip...
Unpacking the package...
Installing the plugin...
Plugin installed successfully.
Activating 'woocommerce'...
Plugin 'woocommerce' activated.
Success: Installed 1 of 1 plugins.

Ce que cela signifie : Vous avez remplacé les fichiers du plugin par un ensemble cohérent et l’avez réactivé.

Décision : Retestez les flux critiques (checkout, connexion, admin). Si c’est un plugin critique pour le chiffre d’affaires, n’assumez pas que « activé » signifie « sain ».

Task 17: Check the web server error logs for permission/rename failures during update

cr0x@server:~$ sudo tail -n 80 /var/log/nginx/error.log
2025/12/27 11:42:18 [error] 21011#21011: *4411 FastCGI sent in stderr: "PHP message: PHP Warning:  rename(/var/www/example.com/public/wp-content/plugins/akismet,/var/www/example.com/public/wp-content/plugins/akismet.old): Permission denied" while reading response header from upstream, client: 203.0.113.50, server: example.com, request: "POST /wp-admin/update.php?action=upgrade-plugin HTTP/2.0"

Ce que cela signifie : WordPress a tenté de renommer des répertoires dans le cadre de la mise à jour et a reçu un Permission denied.

Décision : Corrigez ownership/ACLs, puis relancez les mises à jour. Sinon ça échouera à chaque fois, généralement à l’étape de renommage.

Task 18: Fix ownership for a “WordPress updates itself” model (opinionated, but common)

cr0x@server:~$ sudo chown -R www-data:www-data /var/www/example.com/public/wp-content

Ce que cela signifie : PHP peut maintenant écrire dans wp-content. (Vous pourriez aussi avoir besoin d’un accès en écriture à la racine pour les mises à jour core, selon votre modèle.)

Décision : Si vous faites des déploiements immuables, ne faites pas cela. Désactivez plutôt les mises à jour depuis l’interface et poussez les changements via pipeline.

Task 19: Clear caches that may be replaying the maintenance page

cr0x@server:~$ sudo -u www-data bash -lc 'cd /var/www/example.com/public && wp cache flush'
Success: The cache was flushed.

Ce que cela signifie : Le cache d’objet WordPress a été vidé (cela fonctionne avec certains backends de cache ; selon la configuration).

Décision : Si vous avez un cache de pages séparé (Nginx FastCGI cache, Varnish, CDN), purgez‑le aussi. Si vous ne pouvez pas purger, contournez au moins et confirmez la santé de l’origine.

Task 20: Validate HTTP status and body after fixes

cr0x@server:~$ curl -sS -D- -o /dev/null https://example.com/ | sed -n '1,15p'
HTTP/2 200
date: Sat, 27 Dec 2025 12:09:07 GMT
content-type: text/html; charset=UTF-8
server: nginx

Ce que cela signifie : Vous êtes revenu à 200 OK.

Décision : L’incident n’est pas clos tant que vous n’avez pas confirmé que les pages clés et les actions d’admin sont saines, et que vous avez traité la cause sous‑jacente (espace, permissions, processus de mise à jour).

Trois mini-récits du monde de l’entreprise depuis le terrain

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

Une entreprise de taille moyenne exécutait WordPress derrière un CDN et un WAF, avec un cluster d’origine séparé. Le marketing a programmé une « petite mise à jour de plugin » quinze minutes avant une annonce produit.
Quelqu’un a vu la bannière de maintenance et a fait ce que l’internet recommande : supprimer .maintenance sur un nœud d’origine. La bannière est restée.

L’hypothèse erronée était subtile : ils ont supposé que la bannière était générée par l’origine au moment du rafraîchissement. Ce n’était pas le cas. Le CDN avait mis en cache la réponse 503 de maintenance pendant une durée étonnamment longue à cause d’une règle edge destinée à protéger l’origine pendant les pannes. Il considérait 503 comme mise en cache « pour réduire la charge ».

Pendant ce temps, la mise à jour avait réussi sur deux nœuds et échoué sur un. Le cluster était en état de split‑brain : certains nœuds servaient le plugin mis à jour, un nœud avait un répertoire partiel et générait des fatales, et l’edge rejouait joyeusement la page de maintenance depuis le cache.

La correction n’a rien d’héroïque. Ils ont purgé le cache CDN pour les chemins affectés, retiré le nœud cassé de la rotation, réinstallé proprement le plugin, puis réintroduit le nœud.
Mais la leçon est restée : quand vous voyez un message générique, vous ne pouvez pas présumer où il a été généré. Vérifiez la couche d’abord.

Leur action post‑incident a été simple et efficace : rendre les réponses 503 non‑cacheables à l’edge sauf si explicitement autorisé, et ajouter un contrôle « bypass origine » au runbook d’astreinte.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une autre organisation a décidé de « accélérer » WordPress en déplaçant wp-content sur un stockage réseau afin que plusieurs têtes web partagent les uploads et plugins. Ça fonctionnait bien en trafic normal.
Les mises à jour, en revanche, sont devenues une roulette russe.

Le jour de la mise à jour, un zip de plugin se téléchargeait, l’extraction commençait, puis le système de fichiers se bloquait pendant des secondes entières. Les pics de latence NFS faisaient que les renommages de répertoires et opérations metadata prenaient assez de temps pour que les requêtes PHP atteignent des timeouts.
WordPress mourait en plein upgrade, laissant .maintenance et un répertoire de plugin à moitié déplacé.

L’équipe a tenté de compenser en augmentant les timeouts PHP et en ajoutant des retry. Cela a rendu le site « plus tolérant » mais a aussi ralenti et rendu les échecs plus difficiles à détecter. Les utilisateurs restaient plus longtemps en mode maintenance. L’astreinte restait plus longtemps en réunion. Tout le monde a perdu.

La correction ennuyeuse a été de cesser d’optimiser la mauvaise chose : ils ont remis le code plugins/thèmes sur le disque local de chaque nœud et n’ont gardé que les uploads sur le stockage partagé. Les déploiements ont synchronisé les changements de plugin via des artefacts.
Les mises à jour ont cessé de rester bloquées parce que le chemin critique n’était plus dépendant d’appels metadata d’un système de fichiers réseau bavard.

Quand on dit « le stockage est lent », on veut généralement dire « la metadata est lente ». Les mises à jour WordPress sont surtout des opérations metadata déguisées en zip.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la situation

Une entreprise avec un WordPress fortement personnalisé suivait un processus de release strict : staging d’abord, puis production, avec des mises à jour pilotées par WP-CLI et une vraie procédure de rollback.
Personne n’avait le droit de cliquer sur « Mettre à jour » en production, ce qui rendait l’UI admin un peu moins excitante. L’internet a survécu.

Un après‑midi, des mises à jour automatiques de traduction ont déclenché brièvement le mode maintenance, puis le site est revenu à la normale. Quelques minutes plus tard, le taux d’erreurs a augmenté dans la supervision—pas à cause du mode maintenance, mais d’un conflit d’autoloader d’un plugin qui ne se manifestait que sous un certain état de cache.

Parce qu’ils avaient des logs, des métriques et un artefact connu bon, ils n’ont pas commencé à « réparer » la production manuellement. Ils ont rollbacké vers l’artefact précédent sur tous les nœuds, désactivé le canal de mises à jour automatiques qui a introduit le changement, et restauré le service de façon cohérente.
Puis ils ont reproduit le problème en staging et l’ont corrigé proprement.

Leur grande victoire n’a pas été une commande astucieuse. C’était la discipline : source unique de vérité pour le code, déploiements reproductibles, et la capacité de revenir en arrière sans négocier avec un répertoire de plugin à moitié écrit.

Blague n°2 : La stratégie de mise à jour WordPress la plus fiable reste « ne pas faire d’opération chirurgicale en direct », ce qui est aussi mon conseil pour la plupart des loisirs.

Erreurs courantes : symptôme → cause racine → correctif

C’est la partie où vous arrêtez de deviner. Faites correspondre votre symptôme à une cause probable et appliquez le correctif spécifique.

1) Symptom: Maintenance banner stays for hours; site returns 503

  • Cause racine : Fichier .maintenance périmé laissé après une mise à jour interrompue.
  • Correctif : Supprimez .maintenance à la racine WordPress ; puis vérifiez l’intégrité plugin/thème/core et les logs pour trouver ce qui a échoué.

2) Symptom: Banner is gone after deleting .maintenance, but now you get a white screen (500)

  • Cause racine : Mise à jour partielle d’un plugin/thème causant une erreur PHP fatale.
  • Correctif : Consultez les logs PHP, puis réinstallez ou restaurez le plugin/thème cassé. Utilisez WP-CLI quand c’est possible. Ne « supprimez pas des dossiers au hasard ».

3) Symptom: Some users see the banner, others don’t

  • Cause racine : CDN ou reverse proxy mettant en cache la réponse de maintenance ; ou plusieurs origines avec état incohérent.
  • Correctif : Testez l’origine directement, purgez les caches, et assurez‑vous que tous les nœuds ont le même code. Retirez les nœuds cassés de la rotation.

4) Symptom: Updates always fail and maintenance mode often sticks

  • Cause racine : Mismatch de permissions/ownership ; l’utilisateur PHP ne peut pas renommer/écrire des répertoires.
  • Correctif : Choisissez un modèle : soit autoriser WordPress à écrire (ownership/ACLs), soit désactiver les mises à jour depuis l’interface et déployer via CI/CD.

5) Symptom: Update starts, then hangs; server load spikes; I/O wait climbs

  • Cause racine : Stockage lent ou latence du système de fichiers réseau pendant les opérations unzip/rename.
  • Correctif : Déplacez le code sur le disque local, gardez le stockage partagé pour les uploads seulement, ou refondez les mises à jour pour être basées sur des artefacts. Analysez les goulots I/O et l’utilisation des inodes.

6) Symptom: Maintenance message keeps reappearing right after you remove it

  • Cause racine : Un autre processus de mise à jour échoue et recrée .maintenance de façon répétée, souvent via les mises à jour automatiques ou cron.
  • Correctif : Désactivez temporairement les mises à jour automatiques, inspectez les jobs cron, et localisez le composant qui échoue via les logs et la sortie WP-CLI des mises à jour.

7) Symptom: Only /wp-admin shows issues; front-end looks okay

  • Cause racine : Point de terminaison de mise à jour côté admin qui échoue ; peut être dû à des timeouts PHP, des règles WAF bloquant les POST, ou un plugin cassé chargé uniquement en admin.
  • Correctif : Vérifiez les logs WAF, les timeouts PHP, et les erreurs spécifiques à l’admin. Mettez à jour via WP-CLI pour contourner les timeouts du navigateur.

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

Checklist de restauration d’urgence (remettre les utilisateurs en ligne)

  1. Vérifier la couche : La réponse de maintenance provient‑elle de l’origine ou est‑elle mise en cache en amont ?
  2. Vérifier .maintenance : S’il est présent et périmé, supprimez‑le.
  3. Retester : Confirmer HTTP 200 et que la page d’accueil s’affiche.
  4. Vérifier les logs : Chercher des fatales PHP et des erreurs de permissions pendant la fenêtre de mise à jour.
  5. Réparer le composant cassé : Réinstaller/restaurer le plugin/thème/core si nécessaire.
  6. Stabiliser le stockage : Assurer que l’espace disque et les inodes ne sont pas presque pleins.
  7. Purger les caches : Cache d’objet + cache de page + cache CDN selon le besoin.
  8. Valider les chemins critiques : Connexion, panneau d’administration, et tout flux générant du revenu.

Plan de récupération contrôlée (lorsque vous suspectez des mises à jour partielles)

  1. Mettre le site en maintenance intentionnelle (optionnel) : Si vous avez un vrai plugin/page de maintenance, utilisez‑le au lieu de compter sur le chaos de .maintenance.
  2. Identifier la mise à jour exacte qui a échoué : Utilisez les listes WP-CLI et les horodatages des logs.
  3. Rollback ou réinstallation propre : Remplacez les répertoires entiers de plugin/thème ; n’essayez pas de patcher manuellement des fichiers manquants.
  4. Vérifier les checksums du core : Confirmez l’intégrité de base avant de tout accuser.
  5. Relancer les mises à jour une par une : Surveillez les logs pendant chaque mise à jour.
  6. Documenter la cause racine : Disque, inodes, permissions, caching, ou modèle de processus—choisissez une cause principale et corrigez‑la.

Checklist modèle opérationnel (choisissez votre stratégie)

C’est ici que les équipes arrêtent de marcher dans les mêmes pièges. Décidez comment les mises à jour se déroulent dans votre environnement :

  • Modèle A : WordPress se met à jour lui‑même sur le serveur. Alors vous devez assurer un ownership/ACLs correct, suffisamment d’espace/inodes, et des règles de cache sûres.
  • Modèle B : Déploiements immuables (recommandé pour la production sérieuse). Alors désactivez les mises à jour depuis l’interface, construisez des artefacts en CI, et déployez atomiquement avec rollback.

Le modèle A peut fonctionner. Le modèle B monte mieux en charge. Les mélanger produit l’incident où tout le monde a raison et le site est toujours down.

Prévention : arrêter de revivre cet incident

Arrêtez de faire des « Tout mettre à jour » en production

Mettez à jour un composant à la fois. Surveillez le système. Si ça échoue, vous saurez ce qui a cassé.
« Tout mettre à jour » est efficace pour les humains et brutal pour le débogage.

Donnez aux mises à jour les ressources dont elles ont besoin

Les mises à jour ne demandent pas beaucoup de calcul, mais elles sollicitent fortement le système de fichiers. Cela signifie :

  • Gardez une véritable marge disque (pas « 99% utilisé mais techniquement OK »).
  • Surveillez les inodes, surtout sur les petits systèmes root et les couches overlay des conteneurs.
  • Évitez d’exécuter le code plugin/thème sur des systèmes de fichiers réseau lents si vous pouvez.

Faites en sorte que le cache respecte la réalité

Si votre edge met en cache les 503 pendant de longues périodes, vous choisissez des « pannes plus rapides ». Parfois défendable. Souvent ce n’est que de la configuration héritée.
Assurez‑vous que votre CDN/proxy traite les réponses de maintenance comme non‑cacheables sauf si vous voulez explicitement ce comportement.

Logger et observer les mises à jour comme si vous y teniez

WordPress est un logiciel applicatif. Les mises à jour sont des déploiements. Traitez‑les comme tels :

  • Centralisez les erreurs PHP.
  • Enregistrez l’heure des mises à jour (même un simple journal des changements aide).
  • Alarmez sur des taux 503 soutenus et des pics d’erreurs pendant la fenêtre de mise à jour.

Utilisez WP-CLI pour les mises à jour, surtout sur les sites chargés

Les mises à jour via le navigateur sont fragiles : elles reposent sur une seule requête HTTP qui doit survivre assez longtemps. Les mises à jour WP-CLI sont plus contrôlables, plus faciles à logger, et s’exécutent dans une session qui ne meurt pas quand votre laptop perd le Wi‑Fi.

Une citation pour rester lucide

« L’espoir n’est pas une stratégie. » — General Gordon R. Sullivan

Pas besoin de devenir philosophe. Arrêtez simplement de compter sur « ça se règle généralement tout seul » comme plan opérationnel.

FAQ

1) Est‑il sûr de supprimer le fichier .maintenance ?

La plupart du temps, oui—si la mise à jour n’est pas en cours. Le supprimer enlève le verrou. Le risque est d’exposer les utilisateurs à un site partiellement mis à jour. Si vous suspectez des mises à jour partielles, supprimez le verrou puis vérifiez immédiatement les logs et réinstallez le composant cassé.

2) Où se trouve exactement .maintenance ?

Dans le répertoire racine de WordPress—généralement le même dossier qui contient wp-config.php, wp-admin, et wp-includes. Pas à l’intérieur de wp-content.

3) Pourquoi WordPress renvoie‑t‑il un 503 pendant la maintenance ?

Parce que c’est le signal correct aux clients et aux caches : « service temporairement indisponible ». Le problème survient quand les caches le gèrent mal, ou quand « temporairement » devient « jusqu’à l’arrivée d’un humain ».

4) Le fichier est parti, mais je vois encore le message de maintenance. Et maintenant ?

Suspectez d’abord le cache. Testez l’origine directement et purgez le CDN/reverse‑proxy/cache de pages. Si l’origine renvoie 200 mais l’edge sert encore 503, ce n’est plus WordPress—c’est l’état du cache.

5) Un plugin peut‑il déclencher le mode maintenance sans que je le mette à jour ?

Oui. Les mises à jour automatiques, les mises à jour de traduction, et certains mécanismes d’hébergeur géré peuvent déclencher la maintenance. Aussi, un plugin peut casser le processus de mise à jour, laissant le verrou même si le déclencheur était autre.

6) Dois‑je désactiver les mises à jour automatiques pour éviter ça ?

Ne désactivez pas les mises à jour de sécurité simplement parce qu’une mise à jour vous a un jour causé du tort. Corrigez plutôt les causes sous‑jacentes : permissions, disque/inodes, et un processus de mise à jour sûr (WP-CLI, staging, artefacts).
Désactiver les mises à jour automatiques échange un incident de fiabilité contre un incident de sécurité. Ce n’est pas un bon marché.

7) Pourquoi cela arrive‑t‑il plus souvent sur l’hébergement mutualisé ?

L’hébergement mutualisé a souvent un disque contraint, une I/O limitée, des permissions étranges, et des timeouts PHP. Le mécanisme de mise à jour WordPress suppose qu’il peut écrire et renommer des fichiers rapidement. Sur du mutualisé, cette hypothèse est souvent fausse.

8) Comment prévenir les mises à jour partielles de plugins ?

Utilisez un modèle de déploiement cohérent. Préférez des déploiements basés sur des artefacts ou au moins des mises à jour WP-CLI exécutées dans une session stable. Assurez‑vous d’avoir suffisamment d’espace/inodes et un ownership/ACLs correct. Évitez de mettre à jour pendant les pics de trafic où les timeouts sont plus probables.

9) Exécuter WordPress sur NFS/EFS aggrave‑t‑il la situation ?

Cela peut. Les mises à jour impliquent beaucoup de petites opérations de fichiers (très métadonnées). Les systèmes de fichiers réseau peuvent introduire des pics de latence qui causent des timeouts et des déplacements partiels. Si vous devez utiliser un stockage partagé, gardez là‑dessus les uploads et déployez le code localement.

10) Quelle est la correction « entreprise » la plus propre ?

Désactivez les mises à jour depuis l’interface en production, construisez des artefacts versionnés en CI, déployez atomiquement, et conservez une voie de rollback. Traitez WordPress comme une application, pas comme un éditeur de fichiers interactif.

Conclusion : prochaines étapes qui aident réellement

Si vous êtes coincé sur « Indisponible temporairement pour maintenance programmée », votre gain le plus rapide est presque toujours :
confirmer origine vs cache, supprimer .maintenance si périmé, puis valider ce que la mise à jour a cassé.
Après cela, corrigez la cause réelle : permissions, disque/inodes, stockage lent, ou un processus de mise à jour qui dépend d’une requête navigateur fragile.

Étapes pratiques suivantes :

  1. Ajoutez « vérifier .maintenance + vérifier disque/inodes + vérifier logs » dans votre runbook d’astreinte.
  2. Choisissez un modèle de mise à jour (auto‑mise à jour ou déploiement immuable) et appliquez‑le.
  3. Rendez les réponses 503 non‑cacheables sauf si vous voulez volontairement des pannes mises en cache.
  4. Utilisez WP-CLI pour des mises à jour contrôlées et journalisées—un composant à la fois.
← Précédent
La pénurie mondiale de puces : quand de minuscules composants ont paralysé des industries entières
Suivant →
De RIVA à GeForce : comment l’empire NVIDIA a commencé

Laisser un commentaire