
El error 429 Too Many Requests indica que un servidor ha decidido que un mismo cliente ha hecho demasiadas peticiones en poco tiempo, y en WordPress puede salir de sitios muy distintos: una regla de limitación de tasa de Cloudflare, la configuración de Nginx del hosting, un plugin de seguridad o una API externa que frena a un plugin. Antes de desactivar nada conviene averiguar qué capa lo genera, porque la solución cambia por completo de una a otra.
Las claves del error 429 en WordPress en 20 segundos
El estado 429 se publicó en 2012 en la RFC 6585 del IETF (Internet Engineering Task Force). Según esa especificación, significa que el usuario ha enviado demasiadas peticiones en un periodo de tiempo determinado, lo que se conoce como limitación de tasa o rate limiting. La respuesta puede incluir la cabecera Retry-After para indicar cuántos segundos hay que esperar, y la RFC deja expresamente sin definir cómo identifica el servidor al usuario o cómo cuenta las peticiones. Por eso cada proveedor lo aplica a su manera: unos cuentan por IP, otros por cookie o por ruta, y algunos ni siquiera usan el código 429 cuando limitan.
Ese último detalle explica muchas confusiones. Un administrador que busca un 429 en sus registros puede encontrarse un 503 si el bloqueo viene de Nginx o de Wordfence, y al revés: un plugin de caché que purga Cloudflare a través de su API puede recibir un 429 que el visitante nunca llega a ver.
Cloudflare. Las reglas de limitación de tasa de su WAF (Web Application Firewall, el cortafuegos de aplicaciones web) cuentan las peticiones que coinciden con una expresión y aplican una acción al superar el umbral. Si la acción es bloquear, el código por defecto de la respuesta es 429, aunque se puede cambiar por cualquier otro entre 400 y 499. Según la documentación de Cloudflare, el plan gratuito permite una sola regla, con periodos de conteo y de mitigación de 10 segundos, contando solo por IP y filtrando únicamente por ruta y por bot verificado. Cloudflare también limita su propia API a 1.200 peticiones cada cinco minutos por usuario, y al superarlas responde 429 a todas las llamadas durante los cinco minutos siguientes, algo que afecta a plugins que purgan caché o sincronizan ajustes.
El servidor web. En Nginx, el módulo limit_req limita peticiones por zona, pero su código de rechazo por defecto es 503, no 429; hay que fijarlo con limit_req_status. Muchos alojamientos aplican reglas propias de este tipo que el cliente no ve, y por eso el soporte del hosting es a veces el único que puede confirmar el origen.
Plugins de seguridad. Wordfence permite limitar por minuto las páginas que ven personas y rastreadores, y los 404 que generan. Según su documentación, quien supera esos límites recibe un 503 temporal, avisa de que valores de 60 peticiones por minuto o menos son «muy estrictos» y propone 120 como ajuste general. Su contador no incluye admin-ajax.php ni los recursos estáticos, aunque sí los 404 de imágenes que faltan. Plugins como Limit Login Attempts Reloaded bloquean temporalmente tras varios intentos fallidos de acceso, lo que deja fuera a un usuario legítimo que se equivoca de contraseña.
El propio WordPress. Hay varias rutas que generan muchas peticiones sin que nadie lo note:
wp-login.php, el objetivo habitual de los ataques de fuerza bruta.xmlrpc.php, la interfaz antigua de publicación remota, muy usada también en ataques automatizados./wp-json/), de la que depende el editor de bloques. Una regla demasiado estricta sobre esa ruta rompe el editor antes que cualquier otra cosa.wp-cron.php, que WordPress dispara durante las visitas para ejecutar tareas programadas.Por último, un plugin que consulta una API externa (un servicio de envío, un traductor, una pasarela) puede quedarse sin cuota. En ese caso el 429 aparece en el registro del plugin o en un aviso del panel, no en el navegador del visitante.
Lo primero es reproducir el error una sola vez con las herramientas de desarrollo del navegador abiertas, en la pestaña Red, y anotar la URL exacta, el método (GET o POST) y la hora. Recargar una y otra vez solo alarga el bloqueo, porque cada intento cuenta. Desde la terminal, este comando muestra las cabeceras de la respuesta sin descargar el contenido:
curl -s -D - -o /dev/null https://tusitio.com/wp-login.phpLenguaje del código: JavaScript (javascript)
Con curl -I se obtiene algo parecido, pero envía una petición HEAD en lugar de GET y algunas reglas la tratan de forma distinta, así que conviene probar las dos. En la salida interesan el código de estado, la cabecera Retry-After si existe, y cabeceras como server: cloudflare o cf-ray, que indican que la respuesta ha pasado por Cloudflare. Que pase por Cloudflare no demuestra que el bloqueo sea suyo: Cloudflare también entrega los 429 que genera el servidor de origen, así que el paso siguiente es mirar el registro de eventos de seguridad de su panel.
En el servidor, Nginx deja una línea en el registro de errores cada vez que rechaza por límite, con el texto limiting requests, excess: … by zone "nombre". Para ver qué IP y qué rutas acumulan respuestas 429 en un registro de acceso con el formato combinado habitual, basta con esto:
awk '$9 == 429 {print $1, $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20Lenguaje del código: JavaScript (javascript)
Si se usa Wordfence, su herramienta de tráfico en vivo muestra quién ha sido limitado y por qué regla. Cuando nada de eso aclara el origen, toca escribir al hosting con la URL, el método, la hora con su zona horaria, las cabeceras recibidas y lo que ya se ha probado, sin incluir cookies ni contraseñas. La pregunta útil no es «quitadme el límite», sino qué capa ha respondido y qué umbral se ha superado.
Si el servidor es propio, lo razonable es limitar solo las rutas sensibles y devolver un 429 claro en lugar del 503 por defecto. Este ejemplo permite de media cinco peticiones por minuto a wp-login.php por IP, con una ráfaga de tres; el bloque PHP debe adaptarse al que ya use el sitio:
# Dentro del bloque http {}
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=5r/m;
# Dentro del bloque server {}
location = /wp-login.php {
limit_req zone=wplogin burst=3 nodelay;
limit_req_status 429;
include fastcgi.conf;
fastcgi_pass php;
}Lenguaje del código: PHP (php)
En una prueba con Nginx 1.24, las cuatro primeras peticiones seguidas pasaron y las siguientes recibieron 429. Si el sitio está detrás de Cloudflare, $binary_remote_addr será la IP de Cloudflare y el límite se aplicará a todos los visitantes a la vez; antes hay que configurar el módulo real_ip con los rangos de Cloudflare y la cabecera CF-Connecting-IP. Para XML-RPC, si ningún servicio lo necesita (conviene comprobarlo antes con Jetpack o con aplicaciones antiguas), lo más directo es cortarlo en el servidor con location = /xmlrpc.php { deny all; }.
En el plan gratuito, la única regla disponible rinde más sobre el acceso que sobre todo el sitio. Una expresión como (http.request.uri.path eq "/wp-login.php") limita el formulario de entrada sin tocar /wp-json/ ni admin-ajax.php, que son las rutas que más peticiones legítimas reciben de los editores. Si los 429 los sufre el propio equipo, la regla está mal acotada. Para proteger el acceso de forma más estricta, wpdirecto ya explicó cómo proteger wp-admin y wp-login.php con Cloudflare Zero Trust.
La frecuencia de Heartbeat se puede espaciar con el filtro heartbeat_settings, en un plugin must-use dentro de wp-content/mu-plugins/. El valor admite de 15 a 120 segundos:
<?php
/**
* Plugin Name: Ajuste de Heartbeat
*/
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 60; // Entre 15 y 120 segundos.
return $settings;
} );Lenguaje del código: HTML, XML (xml)
Con la API REST, el manual oficial desaconseja desactivarla porque rompe funciones del administrador, empezando por el editor de bloques. Si el problema son lecturas anónimas masivas, la alternativa documentada es exigir autenticación con el filtro rest_authentication_errors, o bien aplicar en el borde un límite holgado solo a /wp-json/. Las buenas prácticas con xmlrpc.php y la API REST que publicó wpdirecto siguen siendo válidas.
Para wp-cron, el manual de plugins propone desactivar la ejecución en cada visita y llamar a wp-cron.php desde el programador de tareas del sistema:
// En wp-config.php
define( 'DISABLE_WP_CRON', true );
# En el crontab del usuario del sitio, cada 15 minutos
*/15 * * * * wget -q --delete-after https://tusitio.com/wp-cron.phpLenguaje del código: PHP (php)
En Wordfence, la propia documentación recomienda la acción de ralentizar (throttle) en lugar de bloquear para personas y rastreadores, dejar los límites de páginas en torno a 120 por minuto y reservar el bloqueo para quien genera muchos 404, que suele ser un escáner de vulnerabilidades. También ofrece la opción de dar acceso ilimitado solo a los rastreadores de Google verificados por DNS inverso, que evita limitar a Googlebot sin abrir la puerta a quien se hace pasar por él. Para los bots de IA, el primer filtro sigue siendo robots.txt; plugins como AI Content Signals ayudan a declarar qué usos se permiten, aunque cumplirlo depende de cada rastreador.
Si los 429 o 503 llegan de forma repetida a Googlebot en páginas públicas, conviene revisar después las estadísticas de rastreo de Google Search Console. Un bloqueo aislado en el formulario de acceso no tiene el mismo efecto que un límite que frena a los buscadores en todo el sitio.
Que el servidor, el CDN o un plugin considera que se han enviado demasiadas peticiones en poco tiempo. No es un fallo de WordPress en sí, sino una limitación de tasa aplicada por alguna de las capas que atienden la petición.
Depende de quien lo aplique. Si la respuesta trae la cabecera Retry-After, indica los segundos de espera; en el plan gratuito de Cloudflare la mitigación es de 10 segundos y en Wordfence se configura en sus ajustes.
Revisando las cabeceras con curl y el registro de eventos de seguridad de Cloudflare. Si Cloudflare no registra el bloqueo, hay que buscar en los registros del servidor o preguntar al hosting.
No. La documentación de WordPress advierte de que desactivarla rompe el administrador y el editor de bloques; es mejor exigir autenticación o limitar esa ruta con umbrales holgados.
Fuentes:
