WordPress 429 Demasiadas Solicitudes: bots, límites de tasa, Cloudflare — cómo solucionarlo

¿Te fue útil?

Tu sitio WordPress está “arriba”, pero los usuarios no pueden iniciar sesión, las compras fallan, la API empieza a comportarse mal y Cloudflare responde
amablemente con 429 Demasiadas Solicitudes. Nada grita “plataforma sana” como bloquear a tus clientes de pago porque una granja de bots descubrió tu
/wp-login.php.

Un 429 nunca es un misterio. Es una decisión de política tomada por algo en la ruta de la solicitud—WordPress, un plugin, Nginx/Apache, PHP-FPM, un proxy inverso,
un WAF o Cloudflare. El truco es encontrar qué cosa lo está aplicando, y si te está haciendo un favor o quemando dinero.

Qué significa realmente un 429 en WordPress (y de dónde viene)

HTTP 429 “Demasiadas Solicitudes” significa que el cliente alcanzó un límite de tasa. Ese cliente puede ser un bot, un usuario legítimo, un callback de pasarela de pago, tu propio
comprobador de disponibilidad o una app móvil atrapada en un bucle de reintentos.

En el ecosistema WordPress, el 429 suele ser disparado por una de estas cosas:

  • Cloudflare: limitación de tasa del WAF, Bot Fight Mode, reglas personalizadas o desafíos gestionados.
  • Nginx: reglas limit_req / limit_conn, a veces aplicadas de forma demasiado amplia.
  • Apache: mod_evasive u otros módulos WAF de terceros.
  • Aplicación/plugin: plugins de límite de inicio de sesión, plugins de seguridad, throttling de API o middleware “protector” delante de WP.
  • Proxy/load balancer upstream: limitación de tasa o de conexiones con cabeceras confusas.

Regla operacional clave: 429 no es “un error de WordPress”. Es una decisión de modelado de tráfico. Tu trabajo es identificar quién tomó la decisión,
si fue sensata y cómo ajustarla para que los bots sufran y los humanos no.

Guía de diagnóstico rápido (primeras/segundas/terceras comprobaciones)

Cuando producción está en llamas, no tienes tiempo para depuración interpretativa. Aquí está la ruta más rápida hacia la verdad.

1) Primera comprobación: ¿Cloudflare (u otro borde) genera el 429?

  • Mira las cabeceras de respuesta: server: cloudflare, cf-ray, cabeceras de desafío o una página de error con marca Cloudflare.
  • Compara origen vs borde haciendo curl al origen directamente (salta el CDN si puedes) y ve si el 429 persiste.

Si el 429 está en el borde, arregla primero las reglas de limitación/WAF. No “escales el origen” para apaciguar una regla WAF. Eso es como comprar un segundo frigorífico
porque el primero está cerrado con llave.

2) Segunda comprobación: ¿muestran los logs del origen respuestas 429?

  • Si los logs de acceso del origen muestran 429 para las rutas afectadas, tu origen está aplicando límites.
  • Si los logs del origen muestran mayormente 200/302 mientras los usuarios ven 429, el borde/proxy está bloqueando antes de que el tráfico llegue al origen.

3) Tercera comprobación: identifica el endpoint y la “identidad del cliente” usada para limitar

  • ¿Es /wp-login.php, /xmlrpc.php, /wp-json/, /wp-admin/admin-ajax.php o /?
  • ¿El limitador se basa en IP, cookie, Authorization header o CF-Connecting-IP?
  • ¿Muchos usuarios reales detrás de un NAT (oficina, colegio, operador móvil) están siendo tratados como “un cliente abusivo”?

4) Cuarta comprobación: busca reintentos y bucles de realimentación

  • Un plugin mal configurado, cache roto o un cliente JS puede bombardear un endpoint con reintentos.
  • Los webhooks de pago también pueden reintentar agresivamente si les devuelves 429. Eso puede convertir un “problema pequeño” en “tormenta autosostenida”.

Idea parafraseada (atribuida): Los fallos son normales; la resiliencia viene de diseñar sistemas que siguen funcionando cuando algo falla — Werner Vogels (idea parafraseada).

Datos interesantes e historia: 429, bots y límites de tasa

  • 429 es relativamente nuevo: se estandarizó en RFC 6585 (2012). Antes de eso, la gente metía fallos de límite de tasa en 503 o 403.
  • Retry-After importa: 429 puede incluir una cabecera Retry-After, pero muchas implementaciones la omiten, lo que fomenta tormentas de reintentos torpes.
  • XML-RPC es un imán para el abuso: xmlrpc.php permitía pingbacks y publicación remota; también permitió amplificación y trucos de fuerza bruta durante años.
  • “Bots” no son solo scrapers: credential stuffing, pruebas de tarjetas, acaparamiento de inventario y spam SEO aparecen como “demasiadas solicitudes”.
  • Los CDN hicieron la limitación de tasa algo común: una vez que los bordes pudieron contar solicitudes barato, el throttling se convirtió en política por defecto en vez de un hack del origen.
  • HTTP/2 cambió la forma del abuso: menos conexiones, más solicitudes por conexión; los límites basados en conexiones empezaron a mentirte.
  • El dolor de las IP compartidas es antiguo: la suposición “una IP igual a un usuario” se rompió desde que NAT y proxies corporativos se hicieron normales.
  • El admin-ajax de WordPress se volvió un sumidero de tráfico: temas y plugins lo usaron para todo, a menudo sin caché, convirtiéndolo en un objetivo blando para tormentas.
  • La detección de bots es probabilística: los WAF sacrifican falsos positivos por seguridad. Afinar no es opcional; es operaciones.

Broma #1: La limitación de tasa es como un portero—genial hasta que decide que tus clientes de pago “se ven sospechosos” porque usan el mismo NAT.

Rastrear al que aplica la regla: Cloudflare vs origen vs app

Verás 429 en tres patrones generales. Cada uno apunta a una solución distinta.

Patrón A: Cloudflare devuelve 429 y el origen nunca ve la solicitud

Esto es común cuando las reglas de Rate Limiting de Cloudflare o reglas personalizadas del WAF son demasiado amplias, o activaste un “modo bot” y asumiste que solo ataca bots.
Los 429 de borde normalmente vienen con cabeceras de Cloudflare y una página HTML de error.

Solución: ajusta las reglas de Cloudflare por endpoint y método, y deja de limitar todo. Los humanos mayormente hacen GET. A los bots y a los que prueban credenciales les encantan los POST.

Patrón B: el origen devuelve 429 porque Nginx/Apache está limitando

Normalmente aparece después de que alguien copió un snippet de configuración de blog que limita / o /wp-admin/ sin considerar caché, AJAX o clientes REST.

Solución: limita las ubicaciones correctas, usa la clave correcta para la IP real y establece ráfagas sensatas. La limitación de tasa debe absorber picos, no achatar tu línea base.

Patrón C: WordPress/plugin devuelve 429 o comportamiento tipo 403 informado como 429

Algunos plugins devuelven 429, otros devuelven 403, y algunos devuelven 200 con un mensaje de error. No confíes solo en el navegador; confía en tus logs y cabeceras.

Solución: identifica el plugin/middleware y decide si ajustarlo, reemplazarlo o eliminarlo. Los plugins de seguridad son como cuchillos de cocina: útiles hasta que alguien decide hacer malabarismos.

Bots y patrones de solicitud que disparan 429

No todas las “demasiadas solicitudes” son maliciosas. Solo se parecen a eso a las 3 a. m.

Patrones abusivos comunes

  • Credential stuffing en /wp-login.php: POSTs rápidos, muchos nombres de usuario, mismas gamas de IP, a menudo user agents sin cabeza.
  • Fuerza bruta multicall XML-RPC: menos solicitudes pero cada solicitud contiene múltiples intentos de inicio de sesión.
  • Enumeración de REST API: aporreando /wp-json/wp/v2/users, /wp-json/, endpoints de búsqueda.
  • Golpeteo de admin-ajax de WP: llamadas repetidas a admin-ajax.php desde bots o scripts front-end rotos.
  • Scraping a gran escala: GETs agresivos ignorando cabeceras de caché, a veces con query strings aleatorios para evitar el cache.
  • Pruebas de tarjetas en endpoints de checkout de WooCommerce: muchas transacciones pequeñas o intentos de pago.

Patrones no-maliciosos comunes

  • Usuarios reales detrás de un NAT: una oficina corporativa inicia sesión durante una capacitación; tu limitador por IP entra en pánico.
  • Health checks y monitores de uptime: demasiado frecuentes, desde múltiples regiones, golpeando endpoints no cacheados.
  • Apps móviles: bucles de reintento cuando la red es inestable; pueden parecer un ejército de bots con mala señal.
  • Caché mal configurado: bypass de caché para usuarios logueados genera un pico en el origen y luego se dispara la limitación de tasa.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas son tareas operacionales que puedes ejecutar en un host Linux típico de WordPress. Cada tarea incluye: comando, salida realista, qué significa y qué hacer a continuación.
Ajusta las rutas si tu distro/ubicación de logs difiere.

Task 1: Confirmar quién generó el 429 (las cabeceras dicen la verdad)

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

Qué significa: Cloudflare está emitiendo el 429. El origen puede estar bien—o también podría estar limitando, pero esta respuesta viene del borde.
Decisión: Empieza por ajustes en Cloudflare (rate limit/WAF/bot) antes de tocar Nginx o WordPress.

Task 2: Saltar Cloudflare para probar el origen directamente (si puedes)

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

Qué significa: El origen no devuelve 429. Las políticas de Cloudflare son las culpables primarias.
Decisión: Arregla las reglas del borde; no “mejores el servidor” porque el borde está enojado.

Task 3: Verificar si el origen está devolviendo 429 en los logs de acceso

cr0x@server:~$ sudo awk '$9==429 {count++} END{print count+0}' /var/log/nginx/access.log
312

Qué significa: Nginx del origen devolvió 429 al menos 312 veces en ese archivo de log.
Decisión: Inspecciona la configuración de rate limit de Nginx (limit_req, limit_conn) e identifica las ubicaciones afectadas.

Task 4: Encontrar los endpoints más calientes que reciben 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 /

Qué significa: Login y XML-RPC son los principales afectados.
Decisión: Limitar POST a /wp-login.php, considerar seriamente deshabilitar XML-RPC si no lo necesitas y establecer reglas de Cloudflare por ruta.

Task 5: Identificar las IPs clientes principales que causan 429 (visto por el origen)

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

Qué significa: Un pequeño conjunto de IPs domina el tráfico limitado.
Decisión: Si son claramente abusivas, bloquéalas en Cloudflare/WAF o firewall. Si son NATs corporativos o servicios conocidos, no bloquees—ajusta la clave del limitador.

Task 6: Comprobar si estás usando la IP equivocada como clave (problema con proxy reverso)

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"

Qué significa: La “IP cliente” es una IP de Cloudflare. Si Nginx limita por $binary_remote_addr sin restaurar la IP real,
estás limitando efectivamente a todos los usuarios como uno solo. Así es como creas una fiesta de 429 en todo el sitio.
Decisión: Arregla el manejo de IP real (real_ip_header CF-Connecting-IP; y rangos confiables) antes de ajustar límites.

Task 7: Inspeccionar la configuración de Nginx para directivas de limitación

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;

Qué significa: Existe limitación de tasa. La IP real parece estar configurada (bien), pero confirma que incluiste todos los rangos de proxy relevantes y que está en el contexto correcto.
Decisión: Si el 429 aún afecta a usuarios normales, aumenta rate/burst o cambia la clave a algo más inteligente para tráfico autenticado.

Task 8: Comprobar si PHP-FPM está saturado (429 a veces oculta agotamiento upstream)

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

Qué significa: No concluyente, pero si las conexiones establecidas y timewait son enormes, puedes estar bajo carga. Júntalo con el estado de PHP-FPM si está habilitado.
Decisión: Si el upstream está ahogándose, arregla capacidad y caché; no confíes solo en 429 como defensa.

Task 9: Si el estado de PHP-FPM está habilitado, comprueba la utilización del pool

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

Qué significa: Estás alcanzando max children; el pool se satura a veces. Eso puede causar respuestas lentas, reintentos y luego los límites de tasa disparan upstream.
Decisión: Ajusta PHP-FPM (pm.max_children) y reduce solicitudes dinámicas mediante caché y mitigación específica de endpoints. Escalar PHP sin reducir tráfico de bots es una cinta sin fin.

Task 10: Confirmar si WordPress está siendo golpeado vía XML-RPC

cr0x@server:~$ sudo awk '$7=="/xmlrpc.php" {count++} END{print count+0}' /var/log/nginx/access.log
9812

Qué significa: El tráfico XML-RPC es enorme. A menudo es puro junk.
Decisión: Si no necesitas XML-RPC (Jetpack, algunas apps móviles, integraciones heredadas), bloquéalo en el borde u origen. Si lo necesitas, limita la tasa y añade controles para bots.

Task 11: Detectar intentos de bypass de caché con query string “únicas” en páginas calientes

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

Qué significa: Los bots usan query strings para evitar la caché o disparar nuevas claves de cache.
Decisión: Normaliza o ignora query strings basura en el borde (reglas de caché de Cloudflare) y limita la tasa de patrones sospechosos de query.

Task 12: Identificar user agents detrás de respuestas 429

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

Qué significa: Parte del tráfico es obviamente automatizado (python-requests, curl), pero parte se oculta con UA de navegador.
Decisión: Bloquea la automatización obvia agresivamente; trata los UA con aspecto de navegador con más cautela y apóyate en el comportamiento (tasa, rutas, inicios de sesión fallidos) más que en cadenas.

Task 13: Validar que la restauración de IP real de Cloudflare funcione en 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;
    ...
}

Qué significa: Nginx usará CF-Connecting-IP como la IP cliente cuando las solicitudes vengan de rangos proxy confiables.
Decisión: Asegúrate de que los rangos confiables estén completos y actualizados. Rangos faltantes hacen que algunos POPs aparezcan como “una IP” y tu limitador sea una guillotina.

Task 14: Comprobar iptables/nftables por limitación o bloqueos contundentes

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
  }
}

Qué significa: Hay al menos un bloqueo manual. No generará 429 (descarta), pero puede explicar “fallos aleatorios” que se informan mal.
Decisión: Mantén el bloqueo en el borde cuando sea posible; los bloqueos en el firewall de origen están bien, pero necesitas control de cambios para no bloquear tus propios servicios.

Task 15: Probar rápidamente si 429 se correlaciona con fallos de inicio de sesión (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"

Qué significa: El throttling está ligado al tráfico de login. Eso es bueno—si no atrapa a administradores reales.
Decisión: Añade controles más fuertes para bots, MFA y, idealmente, mueve el login detrás de protecciones adicionales (desafío gestionado de Cloudflare, IPs allowlisted de admin o un hostname admin separado).

Soluciones específicas de Cloudflare que no castigan a usuarios reales

Cloudflare puede arreglar el 80% de los eventos 429 causados por bots, porque detiene el tráfico antes de que toque PHP.
También puede causar el 80% de tus tickets de soporte por bots, porque alguien activó una opción con el entusiasmo de un niño pequeño cambiando interruptores.

Diseño de reglas en Cloudflare: sé preciso, no valiente

Empieza con los endpoints que merecen sospecha:

  • /wp-login.php (POST es lo peligroso)
  • /xmlrpc.php (a menudo es seguro bloquearlo por completo)
  • /wp-json/ (limita por método y por token si tienes uno)
  • /wp-admin/admin-ajax.php (depende del sitio; afina con cuidado)

Haz que tu limitador de Cloudflare refleje tu intención

  • Limita POST más duro que GET. Los humanos navegan; los bots envían formularios.
  • Usa desafíos en lugar de bloqueos cuando los falsos positivos dañen ingresos (checkout, login para miembros).
  • Separa tráfico anónimo y autenticado. Si puedes basarte en la presencia de cookies, hazlo. Las sesiones autenticadas no deberían compartir el mismo bucket que bots anónimos.
  • Protege webhooks. Pasarelas de pago y callbacks de SaaS deben estar allowlisteados por IP/proveedor donde sea posible, o limitados por separado con umbrales más altos.

Manejar la realidad de NAT e IPs compartidas

Los límites por IP son el valor por defecto porque son fáciles. También son incorrectos más a menudo de lo que admitimos.
Puedes reducir daños colaterales:

  • Usando umbrales más altos para endpoints que usuarios legítimos golpean en ráfagas (assets, página principal) y umbrales bajos para endpoints sensibles (login, XML-RPC).
  • Añadiendo score de bot / desafío gestionado para comportamiento abusivo en lugar de 429 duro en la primera ofensa.
  • Eximiendo IPs de salida corporativas conocidas solo cuando estés seguro y tengas buena razón. “Porque ventas no puede iniciar sesión desde el Wi‑Fi del hotel” no es una buena razón.

Caché de Cloudflare como válvula de alivio para limitación de tasa

Si limitas porque el origen no puede manejar la carga, estás usando al portero como ingeniero estructural.
Cachea estáticos y páginas dinámicas cacheables agresivamente en el borde. Cuantas menos solicitudes lleguen a PHP, menos razones tendrás para devolver 429.

Broma #2: La mejor manera de arreglar el tráfico de bots es hacer que sea problema de otra persona—preferiblemente de Cloudflare.

Soluciones en el origen/servidor: Nginx, Apache, PHP-FPM y proxies

Nginx: limita solo lo que realmente quieres limitar

limit_req en Nginx funciona bien cuando:

  • Tienes IPs cliente correctas (restauración de IP real es innegociable detrás de proxies/CDN).
  • Limites por rutas que realmente son sensibles.
  • Permites ráfagas para comportamiento humano (un navegador carga múltiples recursos rápidamente).

Enfoque típico más seguro: define zonas por endpoint. No reutilices una “zona del sitio” a menos que disfrutes tickets de soporte.

Apache: evita “módulos mágicos” que no entiendes

mod_evasive y herramientas similares pueden ayudar, pero tienden a comportarse como un perro guardián entrenado leyendo vibraciones.
Si los usas, asegúrate de poder observar qué bloquean y por qué.

Cadena de proxy inverso: garantiza que la identidad del cliente sobreviva el viaje

Cadena común: Cloudflare → load balancer → Nginx → PHP-FPM → WordPress.
La limitación en cualquier capa de la cadena debe estar de acuerdo sobre qué significa “cliente”. Si una capa ve todas las solicitudes como provenientes del proxy, tu limitador tratará a todo Internet como una persona.

PHP-FPM: no trates síntomas solo con throttles

Si PHP-FPM está en max children y haciendo cola, ya estás en zona de peligro. La limitación puede prevenir un colapso total, pero aún necesitas:

  • Arreglar la caché (page cache, object cache, cache en el borde donde sea posible).
  • Eliminar endpoints calientes y no-cacheados que no necesitan ser dinámicos.
  • Reducir plugins costosos o consultas que disparan tiempo CPU por solicitud.

Soluciones en WordPress/app: login, XML-RPC, REST API, plugins

Deja de tratar wp-login como una API pública

/wp-login.php es la puerta principal a tu administración. También es el endpoint más atacado en la plataforma. Pasos prácticos:

  • Habilita MFA para todos los administradores. Esto no reduce solicitudes, pero reduce el impacto si los intentos tienen éxito.
  • Limita intentos de login (con cuidado). Prefiere herramientas que se integren con Cloudflare o inteligencia de IP, no solo contadores por IP.
  • Considera un hostname de admin separado con reglas de Cloudflare más estrictas, o allowlisting para el acceso del personal.

XML-RPC: si no lo necesitas, bloquéalo

En 2025, la mayoría de sitios no necesitan XML-RPC. Si no usas funciones de Jetpack que dependen de ello, o publicación remota heredada, bloquea /xmlrpc.php.
Si lo necesitas, limita la tasa y añade desafío gestionado de Cloudflare. No lo dejes abierto esperando que tu plugin de seguridad “lo maneje”.

REST API: limita con inteligencia y autentica correctamente

La REST API es útil y comúnmente abusada. Limita los endpoints que son costosos o sensibles.
Si provees APIs a socios/apps móviles, construye un mecanismo de auth distinto y limita por token, no por IP.

admin-ajax.php: la fábrica silenciosa de solicitudes

Muchos temas y plugins llaman a /wp-admin/admin-ajax.php para funciones que podrían cachearse o servirse estáticamente.
Un único script roto puede golpearlo repetidamente, y entonces tu limitador bloqueará con gusto a todos los demás que intenten hacer algo dinámico.

Acción: identifica qué acciones son llamadas con frecuencia, cachea respuestas donde sea seguro y mueve funcionalidad pública a endpoints REST con caché y mejores semánticas de throttling.

Tres microhistorias de la vida corporativa

Microhistoria 1: El incidente causado por una suposición equivocada

Una empresa mediana tenía un portal de clientes basado en WordPress detrás de Cloudflare. Añadieron limitación de tasa en Nginx para “proteger el login” y el ingeniero on-call
se sintió bien al respecto. El límite era modesto—una solicitud por segundo con una pequeña ráfaga—aplicado a /wp-login.php.

Lunes por la mañana: ola repentina de errores 429, pero solo para empleados. Los clientes estaban mayormente bien. El soporte escaló, el canal de incidentes se llenó,
y alguien sugirió “Cloudflare se cayó otra vez”, que es la versión moderna de culpar a Mercurio retrógrado.

La suposición equivocada fue simple: pensaron que Nginx veía IPs cliente reales. No era así. Los logs de Nginx mostraban la misma IP para todas las solicitudes: una salida de Cloudflare.
Así que el rate limiter trató a cada empleado (y algunos clientes) como un único cliente porque estaban detrás de la misma identidad de proxy.

La solución también fue simple y algo embarazosa: configurar correctamente la restauración de IP real y confirmar que funciona observando logs. Una vez Nginx vio IPs clientes reales, el rate limiter
se comportó como una herramienta en lugar de una broma.

Acción post-incidente: ningún cambio en limitación sin un paso de validación que verifique que la clave del limitador coincide con la identidad cliente prevista.
No es glamuroso. Extremadamente efectivo.

Microhistoria 2: La optimización que salió mal

Otro equipo quería un admin más rápido. Activaron reglas de caché agresivas y endurecieron la seguridad de Cloudflare. También añadieron una regla:
“Desafía a cualquier usuario que solicite /wp-admin/ más de N veces por minuto.” Parecía razonable—los admins no deberían spamear páginas de admin, ¿verdad?

Luego desplegaron un plugin de dashboard. El plugin usaba la REST API y admin-ajax para sondear cada pocos segundos actualizaciones. En staging, con dos admins,
nadie notó nada. En producción, durante un periodo de reporting trimestral, docenas de empleados abrieron el dashboard a la vez.

Cloudflare vio un pico en solicitudes a endpoints de admin y empezó a desafiar y limitar. El flujo de desafío causó que el plugin reintentara. Reintentos aumentaron
la tasa de solicitud. La tasa de solicitud disparó más desafíos. Su “optimización” creó un bucle de realimentación donde cada intento de usar la UI de admin
incrementaba la probabilidad de ser bloqueado.

La solución fue dejar de vigilar las páginas de admin por tasa bruta y en su lugar enfocar en el subconjunto peligroso: logins fallidos y POSTs sospechosos.
También redujeron el intervalo de sondeo del plugin y cachearon respuestas API costosas. Los admins siguieron siendo productivos, los bots sufrieron y el sistema dejó de devorarse a sí mismo.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Una marca minorista ejecutaba WooCommerce a escala con Cloudflare en frente. Tenían una práctica que sonaba aburrida en reuniones: cada trimestre hacían una “auditoría de forma de tráfico.”
Era una lista de verificación: confirmar configuración de IP real en origen, revisar reglas WAF/rate limit, verificar allowlists de webhooks y ejecutar pruebas sintéticas contra checkout y login.

Durante una auditoría notaron un aumento gradual de 429 en endpoints /wp-json/. Aún no había fallo. Pero vieron un patrón:
integraciones de socios estaban mudándose de llamadas servidor-a-servidor a un SDK móvil que compartía IPs por NAT de operador.

Porque tenían logs y líneas base, no esperaron a una caída. Ajustaron límites para que la clave fuera tokens de API, no IPs, y crearon reglas de Cloudflare separadas
para clientes API autenticados. También añadieron semántica Retry-After en el origen para un endpoint interno, para evitar tormentas de reintentos.

Más tarde, una campaña de bots golpeó su login y búsqueda de productos duro. El borde la absorbió, el origen se mantuvo estable y los clientes siguieron comprando.
Nadie recibió un trofeo. Consiguieron algo mejor: un fin de semana tranquilo.

Errores comunes: síntoma → causa raíz → solución

Estos son los modos de fallo que veo repetidamente. Son comunes porque son plausibles. También son evitables si dejas de adivinar.

1) Síntoma: “Todos obtienen 429, incluso la navegación normal”

Causa raíz: limitación de tasa a nivel de sitio (o limitador en /) con umbrales demasiado bajos; o claves del limitador basadas en IP de proxy (todos los usuarios parecen idénticos).

Solución: restaura IPs cliente reales; limita a endpoints sensibles; aumenta burst; excluye assets estáticos; confirma que la caché funciona.

2) Síntoma: “Solo wp-admin está roto, el front-end está bien”

Causa raíz: regla de Cloudflare que desafía/limita endpoints de admin; o tormentas de polling de admin-ajax.

Solución: separa reglas para login de admin vs navegación de admin; reduce polling; usa desafíos gestionados solo donde haga falta; allowlista IPs del personal solo si son estables y con buen gobierno.

3) Síntoma: “El checkout falla intermitentemente con 429”

Causa raíz: reglas WAF/limitación que tratan POSTs de pago como abusivos; reintentos de webhooks causando picos; bots probando tarjetas.

Solución: exime o ajusta endpoints de checkout con umbrales más altos; protége con detección de bots; separa endpoints de webhook y allowlista proveedores conocidos; añade controles antifraude.

4) Síntoma: “Clientes de REST API fallan, la web parece bien”

Causa raíz: límites por IP castigando NAT compartido; claves API no usadas para dar forma al tráfico; reglas de caché de Cloudflare no alineadas con la semántica de la API.

Solución: limita por token; añade un hostname API dedicado; implementa backoff de cliente honrando Retry-After.

5) Síntoma: “429s aumentan justo después de habilitar un plugin de seguridad”

Causa raíz: el plugin bloquea agresivamente, o interpreta IPs CDN como clientes, o trunca admin-ajax/REST usados por tu theme.

Solución: configura proxies confiables; excluye endpoints internos conocidos; reconsidera el plugin. Si no puedes explicar sus decisiones, no lo ejecutes en producción.

6) Síntoma: “429 solo para algunas regiones / ISPs”

Causa raíz: esos clientes comparten IPs de salida; diferencias entre POPs de borde; geobloqueo/limitación por país en Cloudflare.

Solución: audita por colo/región de CF; evita límites agresivos por país; usa reglas basadas en comportamiento en lugar de geografía cuando sea posible.

Listas de verificación / plan paso a paso

Paso a paso: estabiliza primero, luego arregla bien

  1. Confirma al que aplica la regla: borde vs origen vs app (Task 1–3).
  2. Identifica el endpoint: rutas principales con 429 (Task 4).
  3. Valida la identidad del cliente: restauración de IP real y logging (Task 6–7, Task 13).
  4. Clasifica el tráfico: IPs top, UAs, métodos y si es login/REST/ajax (Task 5, Task 12, Task 15).
  5. Aplica mitigaciones dirigidas:
    • Bloquear o desafiar /xmlrpc.php si no se usa.
    • Limitar POST /wp-login.php con una ráfaga humana.
    • Ajustar límites de REST y admin-ajax por método y autenticación.
  6. Reduce la carga en el origen: cachea lo que sea cacheable; confirma que PHP-FPM no está permanentemente saturado (Task 9).
  7. Verifica impacto en usuarios: prueba login, checkout y llamadas API desde redes reales (no solo tu oficina).
  8. Mantén evidencia: captura métricas antes/después y muestras de logs para que el próximo incidente no sea folklore.

Lista operacional: qué cambiar (y qué evitar)

  • Hacer limitar endpoints sensibles (login, XML-RPC, rutas REST específicas).
  • Hacer separar tráfico anónimo del autenticado cuando sea posible.
  • Hacer usar desafíos gestionados para tráfico ambiguo en lugar de bloqueo inmediato.
  • Hacer asegurar que Retry-After esté presente cuando controles la respuesta 429 y los clientes puedan respetarla.
  • Evitar límites por IP a toda la ruta / o a todo /wp-admin/ a menos que disfrutes enseñando a ejecutivos qué es un NAT.
  • Evitar desplegar nuevas reglas WAF/rate sin una prueba canaria y una salida rápida.
  • Evitar “seguridad por montón de plugins.” Una capa bien entendida vence a cinco opacas.

Preguntas frecuentes

1) ¿Un 429 es siempre un problema de bots?

No. A menudo son bots, pero también puede ser tráfico legítimo detrás de NAT, bucles de reintentos, monitores de uptime agresivos o webhooks que reintentan porque los limitaste.
Diagnostica con logs antes de culpar a “bots”.

2) ¿Cómo sé si Cloudflare está devolviendo el 429?

Comprueba cabeceras de respuesta por server: cloudflare, cf-ray y compara con una petición directa al origen (Task 1 y Task 2).
Si el origen nunca ve la solicitud, Cloudflare es el que aplica la regla.

3) ¿Por qué mis empleados reciben 429 pero los clientes no?

A menudo porque los empleados comparten una IP de salida (NAT/VPN de oficina). Un limitador por IP los trata como un único cliente y los limita.
Arregla restaurando IPs reales correctamente y ajustando límites, o usando clave por sesión/token cuando sea posible.

4) ¿Debo simplemente desactivar la limitación de tasa para detener 429?

Temporalmente, tal vez—si estás bloqueando usuarios reales y hay ingresos en juego. Pero no lo dejes desactivado.
La medida correcta es limitación dirigida y mitigación de bots, no volver a “barra libre para atacantes”.

5) ¿Es seguro bloquear xmlrpc.php?

Para muchos sitios, sí. Si dependes de Jetpack o de funcionalidades móviles/legacy que lo usen, bloquear XML-RPC puede romper funcionalidad.
Si no estás seguro, limita y desafía primero, luego mide si algo legítimo lo usa.

6) ¿Puede la caché arreglar errores 429?

Indirectamente. La caché reduce la carga en el origen para que no necesites throttles duros. Pero la caché no detendrá por sí sola fuerza bruta de login o abuso de API.
Usa caché más protecciones por endpoint.

7) ¿Por qué el checkout de WooCommerce dispara 429?

El checkout incluye POSTs, pasos de pago y a veces llamadas a terceros. Las reglas WAF pueden clasificar esto como abusivo, y bots prueban tarjetas ahí.
Crea reglas afinadas para rutas de checkout y protege contra fraude de bots por separado.

8) ¿Cuál es la mejor clave para el limitador: IP, cookie o token?

Para navegación anónima, IP es aceptable con ráfagas sensatas y detección de bots. Para APIs y usuarios autenticados, limitar por token/sesión es mejor.
Limitar solo por IP es frágil en un mundo con NAT y redes móviles.

9) ¿Por qué veo 429 en el navegador pero no en los logs del origen?

Porque algo upstream (Cloudflare, load balancer, WAF) lo está generando antes de que la solicitud alcance el origen. Confirma con comprobaciones de cabeceras y pruebas de bypass al origen.

10) ¿Las respuestas 429 deben incluir Retry-After?

Si controlas la respuesta y los clientes podrían respetarla, sí. Reduce tormentas de reintentos y hace el throttling más predecible.
Para navegadores es menos útil; para clientes API y webhooks, importa.

Conclusión: próximos pasos prácticos

Arreglar errores 429 en WordPress no es “probar ajustes de seguridad al azar hasta que desaparezca la bandera roja.” Es rastrear una decisión a través de tu stack y hacerla más inteligente.
El mejor resultado no es cero 429. El mejor resultado es que los 429 ocurran a propósito contra bots, mientras tus usuarios reales ni se enteran.

  1. Ejecuta la guía de diagnóstico rápido: confirma quién emite el 429 y qué endpoints lo disparan.
  2. Verifica el manejo de IPs cliente de extremo a extremo. Si esto está mal, todo lo demás es espectáculo.
  3. Aplica protecciones dirigidas: desafía/limita POST /wp-login.php, bloquea o ralentiza /xmlrpc.php, afina REST/admin-ajax por método y auth.
  4. Reduce la carga del origen con caché y ajuste de PHP-FPM, para que los límites sean un guardarraíl, no una muleta.
  5. Escribe las reglas y la justificación. Tu yo futuro es otra persona y no merece tus misterios.
← Anterior
Migrar VM de ESXi a Proxmox sin vCenter: exportar OVF/OVA, importar y corregir controladores
Siguiente →
ZFS dRAID: Resilver más rápido — ¿o solo más complejidad?

Deja un comentario