C’était étrange, car de l’extérieur tout fonctionnait. Le site, l’écran de connexion et aussi cette API REST répondaient normalement. Pourtant WordPress lui-même n’était pas d’accord : son propre contrôle, sous Santé du site, signalait que l’API REST était un terrain interdit.
Deux vérités à la fois. Pour un visiteur, tout fonctionnait. Pour le site lui-même, non. Cette différence s’est révélée être la clé, mais je n’en étais pas encore là.
D’abord le mauvais suspect. Ce jour-là, l’administration avait plusieurs fois affiché des choses qui n’étaient plus vraies : une extension supprimée qui figurait encore dans la liste, un message qui restait accroché. Cela sent le cache qui continue à distribuer d’anciennes données. J’ai désactivé ce cache. Cela n’a rien changé.
Le raisonnement tenait debout, et il était pourtant faux. Une explication bien construite n’est pas encore une preuve.
Ce qui se passait vraiment. Un site se parle à lui-même toute la journée. Pour vérifier que quelque chose fonctionne, le serveur demande ses propres pages, comme le ferait un visiteur. La nouvelle extension le fait aussi, avant d’oser activer la double authentification.
Cette extension a un pare-feu. Et dans la liste des adresses bloquées de ce pare-feu figurait l’adresse du serveur web lui-même. La raison était indiquée : trop de demandes de pages qui n’existent pas.
Le site avait donc exclu son propre serveur. Chaque fois que le serveur se demandait quelque chose à lui-même, le pare-feu disait non. Les visiteurs ne remarquaient rien. L’extension, si, et elle refusait donc d’enregistrer un réglage qu’elle ne pouvait pas vérifier.
Comment on en est arrivé là, je ne le sais pas avec certitude. Plus tôt ce jour-là, j’avais installé la mauvaise édition de l’extension et je l’avais retirée avec peine. Pendant un moment, l’extension était à moitié présente. Je suppose que durant ce temps le serveur a sans cesse demandé des fichiers qui n’étaient plus là, et que le pare-feu a compté cela comme une attaque. Je ne l’ai pas mesuré.
La solution cachait encore un piège. Mon assistant IA a retiré l’adresse de la liste de blocage avec une commande et l’a placée sur la liste des adresses de confiance. La commande a annoncé un succès. Le blocage est resté.
L’extension conserve ces listes à deux endroits : dans la base de données et dans un fichier lu à chaque requête. La commande n’avait mis à jour que la base de données. Dans le fichier, l’adresse y était encore. C’est seulement quand elle en a disparu aussi que le serveur a pu de nouveau se joindre lui-même, et que l’interrupteur est resté en place.
Ce que j’en retiens
Mettez l’adresse de votre propre serveur sur la liste des adresses de confiance avant d’activer un pare-feu. Pas après.
À vrai dire, je le savais déjà. C’était dans mes notes d’un autre site, où la même chose s’était produite. Je ne les ai pas consultées à temps.
Si quelque chose fonctionne de l’extérieur et pas de l’intérieur, ne cherchez pas dans le site mais dans ce qui se trouve entre le serveur et lui-même.
Et une commande qui annonce un succès a fait ce qu’elle dit. Pas forcément ce dont vous aviez besoin. Regardez à l’endroit qui compte.
En chemin, l’assistant a lui aussi commis une erreur. Pour contourner le cache pendant les mesures, il a collé un ajout inventé derrière l’adresse. Dans WordPress, cet ajout a un sens : l’archive d’un mois. Elle n’existait pas, donc chaque mesure produisait une « page introuvable ». Exactement ce que le pare-feu comptait.
Pour les techniciens : ce qui se passe exactement
Environnement : WordPress 7 multisite, Really Simple Security Pro dans l’édition multisite, hébergement mutualisé où la machine pour SSH n’est pas la même que le serveur web.
Les symptômes :
- l’interrupteur principal de la 2FA revient en arrière après l’enregistrement, avec le message « REST API blocked »
- Santé du site : le test de l’API REST donne
(403) Forbidden - de l’extérieur,
/wp-json/donne simplement 200, et les fichiers isolés (css, js) aussi, même depuis le serveur
La cause : l’adresse sortante du propre serveur web figure sur la liste de blocage du pare-feu, au motif que le seuil des erreurs 404 a été dépassé. Chaque requête que le serveur s’adresse à lui-même par PHP (loopback) reçoit un 403.
Mesurer sans accès au serveur. Faites récupérer par WordPress lui-même une page de son propre site. C’est possible par l’API REST, en tant qu’utilisateur connecté :
GET /wp-json/wp-block-editor/v1/url-details?url=https://example.com/
Si vous recevez le titre de la page, le serveur se joint lui-même. Si vous ne recevez pas de réponse, comparez avec un fichier css du même site et avec un site externe. Si ceux-là fonctionnent, le problème est dans le loopback.
Attention à curl par SSH. Si la machine sur laquelle vous vous connectez par SSH n’est pas le serveur web, un curl réussi ne prouve rien : la requête vient d’une autre adresse.
Trouver et résoudre :
wp rsssl show_blocked_ips
wp rsssl remove_firewall_ip_block <adresse>
wp rsssl add_firewall_trusted_ip <adresse>
Chez moi, ces commandes n’ont modifié que la base de données. Le fichier wp-content/firewall.php, avec les listes $blocked_ips et $white_list, est resté inchangé. Désactiver le pare-feu n’a pas aidé non plus. Ce qui a fonctionné : retirer de ce fichier la ligne avec l’adresse dans $blocked_ips (une copie d’abord, php -l ensuite).
Le fichier est réécrit à partir de la base de données dès que vous enregistrez quelque chose dans l’écran du pare-feu. L’ordre propre est donc : ajouter les adresses en ligne de commande, enregistrer une fois dans l’écran, puis vérifier dans le fichier qu’elles y sont.
À ne pas utiliser pour contourner le cache : ?m=…. Dans WordPress, c’est l’archive mensuelle. Une valeur qui n’est pas un mois existant donne une 404, et celle-ci compte pour le seuil. Prenez un nom que WordPress ne connaît pas.
À faire au préalable : déclarer comme adresses de confiance celle de votre propre serveur web et celles des services qui gèrent ou surveillent le site de l’extérieur, avant d’activer le pare-feu. L’extension a pour cela deux listes distinctes : une pour le pare-feu et une pour la limitation des tentatives de connexion.



