Votre site WordPress est « en ligne », mais les utilisateurs ne peuvent pas se connecter, le paiement échoue, l’API commence à faire des siennes, et Cloudflare répond aimablement par
429 Too Many Requests. Rien n’annonce une « plateforme saine » comme le blocage de vos clients payants parce qu’une ferme de bots a découvert votre
/wp-login.php.
Un 429 n’est jamais un mystère. C’est une décision de politique appliquée par quelque chose dans votre chemin de requête — WordPress, un plugin, Nginx/Apache, PHP-FPM, un proxy inverse,
un WAF, ou Cloudflare. L’astuce est de trouver quel composant l’impose, et s’il vous rend service ou fait partir de l’argent en fumée.
Ce que signifie réellement un 429 WordPress (et d’où il provient)
HTTP 429 « Too Many Requests » signifie que le client a atteint une limite de débit. Ce client peut être un bot, un utilisateur légitime, un rappel de passerelle de paiement, votre vérificateur de disponibilité,
ou une application mobile coincée dans une boucle de réessai.
Dans l’univers WordPress, un 429 est souvent déclenché par l’un des éléments suivants :
- Cloudflare : règles de limitation de débit du WAF, Bot Fight Mode, règles personnalisées, ou défis gérés.
- Nginx : directives
limit_req/limit_conn, parfois appliquées trop largement. - Apache :
mod_evasiveou modules WAF tiers. - Application/plugin : plugins de limitation de connexions, plugins de sécurité, throttling d’API, ou middleware « protecteur » devant WP.
- Proxy en amont/load balancer : limitation de débit ou de connexions avec des en-têtes confus.
Règle opérationnelle clé : 429 n’est pas « une erreur WordPress ». C’est une décision de gestion du trafic. Votre tâche est d’identifier qui a pris la décision,
si elle était sensée, et comment l’ajuster pour que les bots souffrent et que les humains ne soient pas impactés.
Playbook de diagnostic rapide (premières / secondes / troisièmes vérifications)
Quand la production brûle, vous n’avez pas le temps pour du débogage interprétatif. Voici le chemin le plus rapide vers la vérité.
1) Première vérification : est-ce que Cloudflare (ou un autre edge) génère le 429 ?
- Regardez les en-têtes de réponse :
server: cloudflare,cf-ray, en-têtes de défi, ou une page d’erreur brandée Cloudflare. - Comparez origine vs edge en curlant l’origine directement (bypass du CDN si possible) et vérifiez si le 429 persiste.
Si le 429 se produit à l’edge, corrigez d’abord les règles de limitation/WAF. Ne « scalez pas l’origine » pour apaiser une règle WAF. C’est comme acheter un deuxième frigo parce que le premier est verrouillé.
2) Deuxième vérification : les logs de l’origine montrent-ils des réponses 429 ?
- Si les logs d’accès de l’origine montrent
429pour les chemins concernés, l’origine applique les limites. - Si les logs d’origine montrent majoritairement
200/302alors que les utilisateurs voient429, l’edge/proxy bloque avant que le trafic n’atteigne l’origine.
3) Troisième vérification : identifiez le point de terminaison et « l’identité client » utilisée pour limiter
- Est-ce
/wp-login.php,/xmlrpc.php,/wp-json/,/wp-admin/admin-ajax.phpou/? - Le limiteur utilise-t-il l’IP, le cookie, l’en-tête Authorization ou CF-Connecting-IP comme clé ?
- Beaucoup d’utilisateurs réels derrière un même NAT (bureau, école, opérateur mobile) sont-ils traités comme « un seul client abusif » ?
4) Quatrième vérification : recherchez des réessais et des boucles de rétroaction
- Un plugin mal configuré, un cache cassé ou un client JS peut martyriser un point de terminaison avec des réessais.
- Les webhooks de paiement peuvent aussi réessayer agressivement si vous les 429nez. Cela peut transformer un « petit problème » en « tempête auto-entretenue ».
Idée paraphrasée (attribuée) : Les pannes sont normales ; la résilience vient de la conception de systèmes qui continuent de fonctionner quand tout part en vrille
— Werner Vogels (idée paraphrasée).
Faits et histoire intéressants : 429, bots et limitation de débit
- 429 est assez récent : il a été standardisé dans RFC 6585 (2012). Avant, on mettait les échecs de limitation dans des 503 ou 403.
- Retry-After compte : un 429 peut inclure un en-tête
Retry-After, mais beaucoup d’implémentations l’omettent, ce qui encourage les tempêtes de réessai stupides. - XML-RPC est un aimant à abus : le
xmlrpc.phpde WordPress permettait les pingbacks et la publication distante ; il a aussi permis des amplifications et des attaques par bruteforce pendant des années. - « Bots » n’est pas synonyme de simples scrapers : credential stuffing, tests de cartes, scalping d’inventaire et spam SEO se présentent tous comme « trop de requêtes ».
- Les CDN ont rendu la limitation mainstream : une fois que les edges peuvent compter les requêtes à bas coût, le throttling est devenu une politique par défaut plutôt qu’un bricolage sur l’origine.
- HTTP/2 a changé la forme de l’abus : moins de connexions, plus de requêtes par connexion ; les limites basées sur les connexions ont commencé à mentir.
- La douleur des IP partagées est ancienne : l’hypothèse « une IP = un utilisateur » est cassée depuis que NAT et les proxies d’entreprise sont devenus la norme.
- L’admin-ajax de WordPress est devenu un puits de trafic : thèmes et plugins l’ont utilisé pour tout, souvent sans cache, ce qui en fait une cible facile pour les tempêtes.
- La détection de bots est probabiliste : les WAFs échangent faux positifs contre sécurité. Le tuning n’est pas optionnel ; c’est de l’exploitation.
Blague #1 : La limitation de débit, c’est comme un videur — super jusqu’à ce qu’il décide que vos clients payants « ont l’air suspects » parce qu’ils sont derrière le même NAT.
Traquer l’agent qui impose la règle : Cloudflare vs origine vs application
Vous verrez des 429 selon trois grands schémas. Chacun pointe vers une correction différente.
Motif A : Cloudflare renvoie 429 et l’origine ne voit jamais la requête
C’est courant quand les règles de Rate Limiting Cloudflare ou des règles WAF personnalisées sont trop larges, ou que vous avez activé un « mode bot » en pensant qu’il ne cible que les bots.
Les 429 en edge s’accompagnent typiquement d’en-têtes Cloudflare et d’une page d’erreur HTML.
Correctif : affinez les règles Cloudflare par endpoint et méthode, et arrêtez de limiter tout. Les humains font principalement des GET. Les bots et les credential stuffers adorent les POST.
Motif B : l’origine renvoie 429 parce que Nginx limite le débit
Apparaît souvent après que quelqu’un a copié un snippet de configuration de blog qui limite / ou /wp-admin/ sans tenir compte du caching, des AJAX ou des clients REST.
Correctif : limiter les bons emplacements, choisir la bonne clé pour l’identification du client, et définir des bursts raisonnables. La limitation doit absorber les pics, pas aplatir votre trafic de base.
Motif C : WordPress/plugin renvoie 429 ou comportement type 403 rapporté comme 429
Certains plugins renvoient 429, d’autres renvoient 403, et certains renvoient 200 avec un message d’erreur. Ne vous fiez pas au navigateur seul ; fiez-vous à vos logs et aux en-têtes.
Correctif : identifiez le plugin/middleware, puis décidez de le tuner, de le remplacer ou de le supprimer. Les plugins de sécurité sont comme des couteaux de cuisine : utiles jusqu’à ce que quelqu’un se mette à jongler.
Bots et motifs de requêtes qui déclenchent un 429
Toutes les « trop nombreuses requêtes » ne sont pas malicieuses. Elles ressemblent juste à la même chose à 3 h du matin.
Motifs abusifs courants
- Credential stuffing sur
/wp-login.php: POST rapides, nombreux noms d’utilisateur, mêmes plages IP, souvent des user agents headless. - Brute force multicall XML-RPC : moins de requêtes mais chaque requête contient plusieurs tentatives de connexion.
- Enumération via REST API : martèlement de
/wp-json/wp/v2/users,/wp-json/, endpoints de recherche. - Martèlement de admin-ajax : appels répétés à
admin-ajax.phppar des bots ou des scripts frontend cassés. - Scraping à grande échelle : GET agressifs ignorant les en-têtes de cache, parfois avec des chaînes de requête randomisées pour contourner le cache.
- Tests de cartes sur les endpoints de checkout WooCommerce : nombreuses petites transactions ou tentatives de paiement.
Motifs non malveillants courants
- Utilisateurs réels derrière un NAT : un bureau se connecte pendant une formation ; votre limiteur par IP panique.
- Vérifications de santé et monitors : trop fréquents, depuis plusieurs régions, ciblant des endpoints non mis en cache.
- Applications mobiles : boucles de réessai lorsque le réseau est instable ; elles ressemblent à une armée de bots avec un signal catastrophique.
- Caching mal configuré : contournement du cache pour les utilisateurs connectés provoque un pic à l’origine, puis la limitation se déclenche.
Tâches pratiques : commandes, sorties et décisions (12+)
Ce sont des tâches opérationnelles que vous pouvez exécuter sur un hôte Linux WordPress typique. Chaque tâche inclut : commande, sortie réaliste, ce que cela signifie, et ce que vous faites ensuite.
Adaptez les chemins si votre distribution/emplacement des logs diffère.
Task 1: Confirm who generated the 429 (headers tell the truth)
cr0x@server:~$ curl -sSI https://example.com/wp-login.php | sed -n '1,25p'
HTTP/2 429
date: Sat, 27 Dec 2025 10:12:01 GMT
content-type: text/html; charset=UTF-8
server: cloudflare
cf-ray: 85a1b2c3d4e5f678-FRA
retry-after: 10
Ce que cela signifie : Cloudflare émet le 429. L’origine peut être correcte — ou peut aussi limiter — mais cette réponse vient de l’edge.
Décision : Commencez par les réglages Cloudflare de rate limit/WAF/bot avant de toucher à Nginx ou WordPress.
Task 2: Bypass Cloudflare to test the origin directly (if you can)
cr0x@server:~$ curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/wp-login.php | sed -n '1,25p'
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Ce que cela signifie : L’origine ne renvoie pas de 429. Les politiques Cloudflare sont la cause principale.
Décision : Corrigez les règles d’edge ; ne « mettez pas à niveau le serveur » parce que l’edge est mécontent.
Task 3: Verify whether the origin is returning 429 in access logs
cr0x@server:~$ sudo awk '$9==429 {count++} END{print count+0}' /var/log/nginx/access.log
312
Ce que cela signifie : Nginx de l’origine a renvoyé 429 au moins 312 fois dans ce fichier de log.
Décision : Inspectez la config de limitation Nginx (limit_req, limit_conn) et identifiez les emplacements affectés.
Task 4: Find the hottest endpoints that are getting 429
cr0x@server:~$ sudo awk '$9==429 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10
180 /wp-login.php
74 /xmlrpc.php
29 /wp-json/wp/v2/users
18 /wp-admin/admin-ajax.php
11 /
Ce que cela signifie : Les login et XML-RPC sont les principaux coupables.
Décision : Limiter les POST vers /wp-login.php, envisager fortement de désactiver XML-RPC si vous n’en avez pas besoin, et définir des règles Cloudflare par chemin.
Task 5: Identify top client IPs causing 429 (as seen by origin)
cr0x@server:~$ sudo awk '$9==429 {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10
91 198.51.100.77
68 198.51.100.12
44 203.0.113.55
Ce que cela signifie : Un petit ensemble d’IPs domine le trafic throttlé.
Décision : Si elles sont clairement abusives, bloquez-les au niveau Cloudflare/WAF ou du pare-feu. Si ce sont des NAT d’entreprise ou des services connus, ne bloquez pas — pointez plutôt le limiteur sur une clé mieux choisie.
Task 6: Check if you’re keying on the wrong IP (reverse proxy gotcha)
cr0x@server:~$ sudo tail -n 3 /var/log/nginx/access.log
172.68.10.25 - - [27/Dec/2025:10:12:01 +0000] "POST /wp-login.php HTTP/1.1" 429 169 "-" "Mozilla/5.0"
172.68.10.25 - - [27/Dec/2025:10:12:02 +0000] "POST /wp-login.php HTTP/1.1" 429 169 "-" "Mozilla/5.0"
172.68.10.25 - - [27/Dec/2025:10:12:03 +0000] "POST /wp-login.php HTTP/1.1" 429 169 "-" "Mozilla/5.0"
Ce que cela signifie : L’« IP client » est une IP Cloudflare. Si Nginx limite par $binary_remote_addr sans restauration du réel IP,
vous limitez effectivement tous les utilisateurs comme un seul. C’est ainsi qu’on crée une fête généralisée de 429.
Décision : Corrigez la gestion du vrai IP (real_ip_header CF-Connecting-IP; et plages trustées) avant d’ajuster les limites.
Task 7: Inspect Nginx config for rate limiting directives
cr0x@server:~$ sudo nginx -T 2>/dev/null | egrep -n "limit_req|limit_conn|limit_req_zone|real_ip_header|set_real_ip_from" | head -30
45: real_ip_header CF-Connecting-IP;
46: set_real_ip_from 173.245.48.0/20;
47: set_real_ip_from 103.21.244.0/22;
120: limit_req_zone $binary_remote_addr zone=wp_login:10m rate=1r/s;
245: limit_req zone=wp_login burst=3 nodelay;
Ce que cela signifie : La limitation existe. Le vrai IP semble configuré (bien), mais confirmez que vous avez inclus toutes les plages de proxy pertinentes et que c’est dans le bon contexte.
Décision : Si des utilisateurs normaux reçoivent encore des 429, augmentez le rate/burst ou changez la clé pour quelque chose de plus intelligent pour le trafic authentifié.
Task 8: Check whether PHP-FPM is saturated (429 sometimes hides upstream exhaustion)
cr0x@server:~$ sudo ss -s
Total: 684
TCP: 412 (estab 96, closed 262, orphaned 0, timewait 262)
Transport Total IP IPv6
RAW 0 0 0
UDP 6 4 2
TCP 150 92 58
INET 156 96 60
FRAG 0 0 0
Ce que cela signifie : Pas concluant, mais si les connexions établies et les timewait sont énormes, vous pouvez être sous charge. Couplez avec le statut PHP-FPM si activé.
Décision : Si l’amont s’étouffe, corrigez la capacité et le caching ; ne comptez pas sur le 429 comme seule défense.
Task 9: If PHP-FPM status is enabled, check pool utilization
cr0x@server:~$ curl -s http://127.0.0.1/php-fpm-status | sed -n '1,20p'
pool: www
process manager: dynamic
start time: 27/Dec/2025:08:00:00 +0000
accepted conn: 124590
listen queue: 0
max listen queue: 47
listen queue len: 128
idle processes: 2
active processes: 38
total processes: 40
max active processes: 40
max children reached: 19
Ce que cela signifie : Vous atteignez le maximum d’enfants ; le pool est saturé par moments. Cela peut conduire à des réponses lentes, des réessais, puis des limites qui se déclenchent en amont.
Décision : Tuner PHP-FPM (pm.max_children) et réduire les requêtes dynamiques via le caching et des mesures spécifiques aux endpoints. Monter PHP sans réduire le trafic bot, c’est courir sur un tapis roulant.
Task 10: Confirm whether WordPress is being hammered via XML-RPC
cr0x@server:~$ sudo awk '$7=="/xmlrpc.php" {count++} END{print count+0}' /var/log/nginx/access.log
9812
Ce que cela signifie : Le trafic XML-RPC est énorme. Souvent, c’est du pur bruit.
Décision : Si vous n’avez pas besoin de XML-RPC (Jetpack, certaines applis mobiles, intégrations legacy), bloquez-le à l’edge ou à l’origine. Si vous en avez besoin, rate-limitez et ajoutez des contrôles anti-bots.
Task 11: Spot “unique query string” cache-bypass attempts on hot pages
cr0x@server:~$ sudo awk '$7 ~ /\?/ {print $7}' /var/log/nginx/access.log | head -5
/?utm_source=bot1
/?a=174563
/?rand=991827
/?__cf_chl_tk=abc123
/?q=cheap-seo
Ce que cela signifie : Les bots utilisent des chaînes de requête pour contourner le cache ou déclencher de nouvelles clés de cache.
Décision : Normalisez ou ignorez les chaînes de requêtes inutiles à l’edge (Cloudflare Cache Rules) et rate-limitez les motifs de requêtes suspects.
Task 12: Identify user agents behind 429 responses
cr0x@server:~$ sudo awk '$9==429 {print $12}' /var/log/nginx/access.log | tr -d '"' | sort | uniq -c | sort -nr | head -10
141 python-requests/2.31.0
88 Mozilla/5.0
61 curl/8.5.0
22 Go-http-client/1.1
Ce que cela signifie : Une partie du trafic est manifestement automatisée (python-requests, curl), mais certains se cachent sous des UA de navigateur.
Décision : Bloquez l’automatisation évidente agressivement ; traitez les UA semblant être des navigateurs avec plus de précaution et basez-vous sur le comportement (taux, chemins, échecs de connexion) plutôt que sur des chaînes.
Task 13: Validate Cloudflare real IP restoration is working in Nginx
cr0x@server:~$ sudo nginx -T 2>/dev/null | sed -n '35,60p'
http {
real_ip_header CF-Connecting-IP;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
real_ip_recursive on;
...
}
Ce que cela signifie : Nginx utilisera CF-Connecting-IP comme IP client quand les requêtes proviennent de plages de proxy de confiance.
Décision : Assurez-vous que les plages trustées sont complètes et à jour. Des plages manquantes font apparaître certains POPs comme « une seule IP » et votre limiteur devient une guillotine.
Task 14: Check iptables/nftables for blunt rate limiting or blocks
cr0x@server:~$ sudo nft list ruleset | sed -n '1,80p'
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
ip saddr 198.51.100.77 drop
}
}
Ce que cela signifie : Il y a au moins un blocage manuel. Ça ne génère pas de 429 (ça droppe), mais cela peut expliquer des « échecs aléatoires » qui sont mal rapportés.
Décision : Continuez à bloquer à l’edge quand c’est possible ; les blocages au pare-feu d’origine sont acceptables, mais vous avez besoin d’un contrôle de changement pour ne pas bloquer vos propres services.
Task 15: Quickly test whether 429 correlates with login failures (credential stuffing)
cr0x@server:~$ sudo grep -E "wp-login\.php|authentication failed|Invalid username" /var/log/nginx/access.log | tail -n 5
198.51.100.77 - - [27/Dec/2025:10:11:52 +0000] "POST /wp-login.php HTTP/1.1" 429 169 "-" "python-requests/2.31.0"
198.51.100.77 - - [27/Dec/2025:10:11:50 +0000] "POST /wp-login.php HTTP/1.1" 429 169 "-" "python-requests/2.31.0"
Ce que cela signifie : Le throttling est lié au trafic de connexion. C’est une bonne chose — si ça ne bloque pas les vrais administrateurs.
Décision : Ajoutez des contrôles anti-bots plus solides, MFA, et idéalement placez la connexion derrière des protections additionnelles (défi géré Cloudflare, IP allowlistée pour les admins, ou un nom d’hôte admin séparé).
Correctifs spécifiques à Cloudflare qui n’ennuient pas les vrais utilisateurs
Cloudflare peut résoudre 80% des événements 429 pilotés par des bots, car il arrête le trafic avant qu’il n’atteigne PHP.
Il peut aussi provoquer 80% de vos tickets de support liés aux bots, parce que quelqu’un a activé un réglage avec l’enthousiasme d’un enfant qui fait sauter les interrupteurs.
Conception des règles Cloudflare : soyez précis, pas téméraire
Commencez par les endpoints qui méritent la suspicion :
/wp-login.php(le POST est le dangereux)/xmlrpc.php(souvent sans risque à bloquer complètement)/wp-json/(limitez par méthode et par token si vous en avez un)/wp-admin/admin-ajax.php(dépend du site ; affinez avec précaution)
Faites correspondre votre limiteur Cloudflare à votre intention
- Limitez les POST plus sévèrement que les GET. Les humains naviguent ; les bots soumettent.
- Utilisez des défis plutôt que des blocages quand les faux positifs nuisent au chiffre d’affaires (checkout, connexion des membres).
- Séparez le trafic anonyme et authentifié. Si vous pouvez utiliser la présence d’un cookie comme clé, faites-le. Les sessions authentifiées ne doivent pas partager le même compartiment que les bots anonymes.
- Protégez les webhooks. Les passerelles de paiement et callbacks SaaS doivent être allowlistés par IP/fournisseur quand c’est possible, ou limités séparément avec des seuils plus élevés.
Gérez la réalité du NAT et des IP partagées
Les limites par IP sont la valeur par défaut parce qu’elles sont simples. Elles sont aussi souvent incorrectes.
Vous pouvez réduire les dommages collatéraux en :
- Utilisant des seuils plus élevés pour les endpoints que les utilisateurs légitimes frappent en rafales (assets, page d’accueil) et des seuils plus faibles pour les endpoints sensibles (login, XML-RPC).
- Ajoutant un score bot / défi géré pour les comportements abusifs au lieu d’un 429 dur au premier écart.
- Exemptant les IP de sortie d’entreprise connues seulement si vous êtes certain et avez une bonne raison. « Parce que l’équipe commerciale ne peut pas se connecter depuis le Wi‑Fi de l’hôtel » n’est pas une bonne raison.
Le caching Cloudflare comme soupape de limitation
Si vous limitez parce que l’origine ne peut pas supporter la charge, vous utilisez le videur comme ingénieur structurel.
Mettez en cache agressivement les pages statiques et dynamiques mises en cache à l’edge. Moins de requêtes atteignent PHP, moins vous aurez de raisons de 429ner qui que ce soit.
Blague #2 : La meilleure façon de régler le trafic bot est d’en faire le problème de quelqu’un d’autre — de préférence Cloudflare.
Correctifs côté origine/serveur : Nginx, Apache, PHP-FPM et proxies inverses
Nginx : ne limitez que ce que vous avez l’intention de limiter
limit_req de Nginx fonctionne bien quand :
- Vous avez des IP clients correctes (la restauration du vrai IP est non négociable derrière des proxies/CDN).
- Vous limitez des chemins réellement sensibles.
- Vous autorisez des bursts pour le comportement humain (un navigateur charge plusieurs ressources rapidement).
Approche typique plus sûre : définir des zones par endpoint. N’utilisez pas une « zone site-wide » à moins d’aimer les tickets de support.
Apache : évitez les modules « magiques » que vous ne comprenez pas
mod_evasive et outils similaires peuvent aider, mais ils se comportent souvent comme un chien de garde dressé à lire des ondes.
Si vous les utilisez, assurez-vous de pouvoir observer ce qu’ils bloquent et pourquoi.
Chaîne de proxy inverse : assurez-vous que l’identité client survit au trajet
Chaîne commune : Cloudflare → load balancer → Nginx → PHP-FPM → WordPress.
La limitation à n’importe quel niveau de la chaîne doit s’accorder sur ce que signifie « client ». Si une couche voit chaque requête comme provenant du proxy, votre limiteur traitera l’internet entier comme une seule personne.
PHP-FPM : ne traitez pas les symptômes par des throttles
Si PHP-FPM est à pm.max_children et en file d’attente, vous êtes déjà en zone de danger. La limitation peut prévenir l’effondrement total, mais vous devez :
- Corriger le caching (cache de pages, cache d’objets, edge cache si possible).
- Éliminer les endpoints chauds non mis en cache qui n’ont pas besoin d’être dynamiques.
- Réduire les plugins coûteux ou les requêtes qui explosent le temps CPU par requête.
Correctifs WordPress/app : connexion, XML-RPC, REST API, plugins
Arrêtez de traiter wp-login comme une API publique
/wp-login.php est la porte d’entrée de votre admin. C’est aussi le point le plus attaqué de la plateforme. Mesures pratiques :
- Activez la MFA pour tous les administrateurs. Ça ne réduit pas les requêtes, mais ça réduit l’impact quand une requête réussit.
- Limitez les tentatives de connexion (avec prudence). Préférez des outils qui s’intègrent à Cloudflare ou à l’intelligence d’IP, pas seulement des compteurs par IP.
- Envisagez un nom d’hôte admin séparé avec des règles Cloudflare plus strictes, ou une allowlist pour l’accès du personnel.
XML-RPC : si vous n’en avez pas besoin, bloquez-le
En 2025, la plupart des sites n’ont pas besoin d’XML-RPC. Si vous n’utilisez pas les fonctionnalités Jetpack qui en dépendent, ou la publication distante legacy, bloquez /xmlrpc.php.
Si vous en avez besoin, limitez et ajoutez un défi géré Cloudflare. Ne le laissez pas grand ouvert en espérant que votre plugin de sécurité « le gère ».
REST API : limitez intelligemment et authentifiez correctement
La REST API est utile et souvent abusée. Limitez les endpoints coûteux ou sensibles.
Si vous fournissez des APIs à des partenaires/applications mobiles, implémentez un mécanisme d’auth distinct et limitez par token, pas par IP.
admin-ajax.php : la fabrique silencieuse de requêtes
Beaucoup de thèmes et plugins frappent /wp-admin/admin-ajax.php pour des fonctionnalités qui pourraient être mises en cache ou servies statiquement.
Un seul script cassé peut le marteler de manière répétée, et alors votre limiteur bloquera joyeusement tous les autres qui essaient d’effectuer quelque chose de dynamique.
Action : identifiez quelles actions sont appelées fréquemment, mettez en cache les réponses quand c’est sûr, et déplacez les fonctionnalités publiques vers des endpoints REST avec cache et de meilleures sémantiques de throttling.
Trois mini-récits issus du monde professionnel
Mini-récit 1 : L’incident causé par une mauvaise hypothèse
Une entreprise de taille moyenne exécutait un portail client WordPress derrière Cloudflare. Ils ont ajouté une limitation Nginx pour « protéger la connexion », et l’ingénieur d’astreinte
était content. La limite était modeste — une requête par seconde avec un petit burst — appliquée à /wp-login.php.
Lundi matin : vague soudaine d’erreurs 429, mais seulement pour les employés. Les clients allaient plutôt bien. Le support a escaladé, le canal d’incident s’est rempli,
et quelqu’un a suggéré « Cloudflare est en panne encore », ce qui est la version moderne de blâmer la rétrogradation de Mercure.
La mauvaise hypothèse était simple : ils pensaient que Nginx voyait les vraies IP clients. Ce n’était pas le cas. Les logs Nginx montraient la même IP pour toutes les requêtes : une sortie Cloudflare.
Donc le limiteur a traité chaque employé (et certains clients) comme un seul client parce qu’ils étaient derrière la même identité de proxy.
La correction était aussi simple et légèrement embarrassante : configurer correctement la restauration du vrai IP et confirmer son fonctionnement en observant les logs. Une fois que Nginx a vu les IP clients réelles, le limiteur s’est comporté comme un outil plutôt que comme une farce.
Action post-incident : aucun changement de limitation sans une étape de validation qui vérifie que la clé du limiteur correspond à l’identité client prévue. Pas glamour. Extrêmement efficace.
Mini-récit 2 : L’optimisation qui s’est retournée contre eux
Une autre équipe voulait un admin plus réactif. Ils ont activé des règles de cache agressives et resserré la sécurité Cloudflare. Ils ont aussi ajouté une règle :
« Challenger tout utilisateur qui demande /wp-admin/ plus de N fois par minute. » Ça semblait raisonnable — les admins ne devraient pas spammer les pages admin, non ?
Puis ils ont déployé un nouveau plugin de dashboard. Le plugin utilisait la REST API et admin-ajax pour interroger toutes les quelques secondes pour des mises à jour. En staging, avec deux admins,
personne n’a remarqué. En production, pendant une période de reporting trimestriel, des dizaines d’employés ont ouvert le tableau de bord en même temps.
Cloudflare a vu un pic sur les endpoints admin et a commencé à challenger et limiter. Le flux de défi a provoqué des réessais du plugin. Les réessais ont augmenté le taux de requêtes. Le taux de requêtes a déclenché plus de défis. Leur « optimisation » a créé une boucle de rétroaction où chaque tentative d’utilisation de l’UI admin augmentait la probabilité d’être bloqué.
La correction finale a été d’arrêter de contrôler les pages admin par le taux brut et de cibler plutôt le sous-ensemble dangereux : échecs de connexion et POSTs suspects.
Ils ont aussi réduit l’intervalle de polling du plugin et mis en cache les réponses API coûteuses. Les admins sont restés productifs, les bots ont souffert, et le système a arrêté de se dévorer.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une marque retail exploitait WooCommerce à grande échelle avec Cloudflare en front. Ils avaient une pratique qui sonnait ennuyeuse en réunion : chaque trimestre, ils réalisaient un « audit de shaping du trafic ».
C’était une checklist : confirmer la config real IP de l’origine, revoir les règles WAF/rate limit, vérifier les allowlists de webhooks, et exécuter des tests synthétiques contre le checkout et la connexion.
Lors d’un audit, ils ont remarqué une augmentation lente des 429 sur les endpoints /wp-json/. Rien de cassé encore. Mais ils ont vu un motif :
des intégrations partenaires passaient d’appels server-to-server à un SDK mobile qui partageait des IP via des NAT d’opérateur.
Parce qu’ils avaient des logs et des baselines, ils n’ont pas attendu une panne. Ils ont ajusté les limites pour keyer sur des tokens API, pas sur les IPs, et créé des règles Cloudflare séparées
pour les clients API authentifiés. Ils ont aussi ajouté des sémantiques Retry-After sur l’origine pour un endpoint interne, pour éviter les tempêtes de réessai.
Plus tard, une campagne de bots a frappé fort leur login et la recherche produit. L’edge a absorbé l’attaque, l’origine est restée stable, et les clients ont continué à finaliser leurs achats.
Personne n’a eu de trophée. Ils ont obtenu quelque chose de mieux : un weekend tranquille.
Erreurs courantes : symptôme → cause racine → correctif
Voici les modes de défaillance que je vois régulièrement. Ils sont courants parce qu’ils sont plausibles. Ils sont aussi évitables si vous arrêtez de deviner.
1) Symptom: “Everyone gets 429, even normal browsing”
Cause racine : limitation site-wide (ou limitation sur /) avec des seuils trop bas ; ou clé du limiteur basée sur l’IP proxy (tous les utilisateurs semblent identiques).
Correctif : restaurez les IP clients réelles ; restreignez la limitation aux endpoints sensibles ; augmentez le burst ; excluez les assets statiques ; confirmez que le caching fonctionne.
2) Symptom: “Only wp-admin is broken, front-end is fine”
Cause racine : règle Cloudflare challenge/limit pour les endpoints admin ; ou tempêtes de polling admin-ajax.
Correctif : règles séparées pour la connexion admin vs la navigation admin ; réduire le polling ; utiliser des défis gérés seulement quand nécessaire ; allowlister les IP du personnel seulement si stable et bien gouverné.
3) Symptom: “Checkout intermittently fails with 429”
Cause racine : règles WAF/limitation traitant les POSTs de paiement comme abusifs ; réessais de webhooks provoquant des rafales ; bots de test de cartes.
Correctif : exemptions ou réglages fins pour les endpoints de checkout avec des seuils plus élevés ; protéger par détection de bots ; séparer les endpoints de webhook et allowlister les fournisseurs connus ; ajouter des contrôles anti-fraude.
4) Symptom: “REST API clients fail, website looks okay”
Cause racine : limites par IP qui pénalisent les NAT partagés ; clés API non utilisées pour le shaping ; règles de cache Cloudflare non alignées avec la sémantique API.
Correctif : limiter par token ; ajouter un nom d’hôte API dédié ; implémenter un backoff client raisonnable respectant Retry-After.
5) Symptom: “429 spikes right after enabling a security plugin”
Cause racine : le plugin bloque agressivement, ou interprète les IPs CDN comme clients, ou throttles admin-ajax/REST utilisés par votre thème.
Correctif : configurez les proxies de confiance ; excluez les endpoints internes connus ; reconsidérez le plugin. Si vous ne pouvez pas expliquer ses décisions, ne le laissez pas en production.
6) Symptom: “429 only for some regions / ISPs”
Cause racine : ces clients partagent des IP de sortie ; différences POP edge ; géoblocage/limitation par pays dans Cloudflare.
Correctif : auditez par colo/région Cloudflare ; évitez les limites agressives par pays ; utilisez des règles basées sur le comportement plutôt que la géographie quand possible.
Listes de contrôle / plan étape par étape
Plan étape par étape : stabiliser d’abord, corriger proprement ensuite
- Confirmez l’agent qui impose : edge vs origine vs app (Task 1–3).
- Identifiez le endpoint : chemins principaux renvoyant 429 (Task 4).
- Validez l’identité client : restauration du vrai IP et logging (Task 6–7, Task 13).
- Classez le trafic : top IPs, UAs, méthodes, et si c’est login/REST/ajax (Task 5, Task 12, Task 15).
- Appliquez des mitigations ciblées :
- Bloquer ou challenger
/xmlrpc.phpsi inutilisé. - Limiter
POST /wp-login.phpavec un burst humain. - Ajuster REST et admin-ajax par méthode et authentification.
- Bloquer ou challenger
- Réduisez la charge de l’origine : cachez ce qui peut l’être ; vérifiez que PHP-FPM n’est pas saturé en permanence (Task 9).
- Vérifiez l’impact utilisateur : testez connexion, checkout, appels API depuis des réseaux réels (pas seulement votre bureau).
- Conservez des preuves : capturez métriques avant/après et échantillons de logs pour que le prochain incident ne soit pas du folklore.
Checklist opérationnelle : quoi changer (et quoi éviter)
- Faire : limiter les endpoints sensibles (login, XML-RPC, routes REST spécifiques).
- Faire : séparer le trafic anonyme du trafic authentifié quand possible.
- Faire : utiliser des défis gérés pour le trafic ambigu au lieu de blocages immédiats.
- Faire : assurer la présence de
Retry-Afterquand vous contrôlez la réponse 429 et que les clients peuvent la respecter. - Éviter : limites blanket par IP sur
/ou sur tout/wp-admin/à moins d’aimer expliquer NAT aux dirigeants. - Éviter : déployer de nouvelles règles WAF/rate sans test canari et sans issue de secours.
- Éviter : « sécurité par empilement de plugins ». Une couche bien comprise vaut mieux que cinq opaques.
FAQ
1) Est-ce qu’un 429 est toujours un problème de bots ?
Non. C’est souvent des bots, mais cela peut être du trafic légitime derrière un NAT, des boucles de réessai, des monitors agressifs, ou des webhooks qui réessaient parce que vous les avez throttlés.
Diagnostiquez avec les logs avant d’accuser les « bots ».
2) Comment savoir si Cloudflare renvoie le 429 ?
Vérifiez les en-têtes de réponse pour server: cloudflare, cf-ray, et comparez avec une requête directe vers l’origine (Task 1 et Task 2).
Si l’origine ne voit jamais la requête, Cloudflare est l’agent qui impose.
3) Pourquoi mes employés obtiennent des 429 mais pas les clients ?
Souvent parce que les employés partagent une IP de sortie (NAT/VPN de bureau). Un limiteur par IP les traite comme un seul client et les throttle.
Corrigez en restaurant correctement les vraies IPs et en ajustant les limites, ou en utilisant l’auth/session/token quand possible.
4) Dois-je juste désactiver la limitation pour arrêter les 429 ?
Temporairement, peut-être — si vous bloquez de vrais utilisateurs et que le chiffre d’affaires est en jeu. Mais ne laissez pas cela désactivé.
La bonne approche est une limitation ciblée et des mitigations anti-bots, pas un retour à « buffet ouvert pour les attaquants ».
5) Est-ce sûr de bloquer xmlrpc.php ?
Pour beaucoup de sites, oui. Si vous dépendez de Jetpack ou de fonctionnalités mobiles/legacy, bloquer XML-RPC peut casser des fonctionnalités.
Si vous n’êtes pas sûr, limitez et challengez d’abord, puis mesurez si quelque chose de légitime l’utilise.
6) Le caching peut-il corriger les erreurs 429 ?
Indirectement. Le cache réduit la charge d’origine donc vous n’avez pas besoin de throttles sévères. Mais le caching n’arrêtera pas le bruteforce de connexion ou l’abus d’API à lui seul.
Utilisez le caching plus des protections spécifiques aux endpoints.
7) Pourquoi le checkout WooCommerce déclenche-t-il des 429 ?
Le checkout comprend des POSTs, des étapes de paiement et parfois des appels tiers. Les règles WAF peuvent mal classer cela comme abusif, et des bots testent des cartes.
Créez des règles affinées pour les chemins de checkout et protégez contre la fraude bot séparément.
8) Quelle est la meilleure clé limiter : IP, cookie, ou token ?
Pour la navigation anonyme, l’IP est acceptable avec des bursts sensés et une détection bot. Pour les APIs et les utilisateurs authentifiés, la limitation basée sur token/session est meilleure.
La limitation uniquement par IP est fragile dans un monde plein de NAT et de réseaux mobiles.
9) Pourquoi je vois un 429 dans le navigateur mais pas dans les logs d’origine ?
Parce que quelque chose en amont (Cloudflare, load balancer, WAF) génère la réponse avant que la requête n’atteigne l’origine. Confirmez avec les en-têtes et les tests de contournement d’origine.
10) Les réponses 429 devraient-elles inclure Retry-After ?
Si vous contrôlez la réponse et que les clients peuvent la respecter, oui. Ça réduit les tempêtes de réessai et rend la limitation plus prévisible.
Pour les navigateurs, c’est moins utile ; pour les clients API et les webhooks, ça compte.
Conclusion : étapes pratiques suivantes
Corriger les erreurs 429 WordPress n’est pas « essayer des réglages de sécurité au hasard jusqu’à ce que la bannière rouge disparaisse ». C’est tracer une décision à travers votre pile et la rendre plus intelligente.
Le meilleur résultat n’est pas zéro 429. Le meilleur résultat, ce sont des 429 qui arrivent aux bots, intentionnellement, pendant que vos vrais utilisateurs ne remarquent rien.
- Exécutez le playbook de diagnostic rapide : confirmez qui émet le 429 et quels endpoints le déclenchent.
- Vérifiez la gestion des vraies IPs de bout en bout. Si c’est faux, tout le reste est du théâtre.
- Appliquez des protections ciblées : challenge/limite
POST /wp-login.php, bloquez ou throttlez/xmlrpc.php, ajustez REST/admin-ajax par méthode et auth. - Réduisez la charge de l’origine avec du caching et le tuning PHP-FPM, afin que les limites deviennent des garde-fous — pas une béquille.
- Notez les règles et les raisons. Le vous du futur est une autre personne et n’a pas besoin de vos mystères.