...

Limitación de tasa de NGINX: protección eficaz contra el tráfico de bots y los ataques

Tasa de NGINX Limiting detiene las solicitudes automatizadas, reduce la carga máxima y protege los puntos finales de inicio de sesión, API y formularios frente a bots y ataques. Te voy a enseñar cómo definir límites y cómo aplicarlos a Protección contra bots lo aplica y, a partir de ahí, elabora un plan de seguridad sólido para sitios web muy visitados.

Puntos centrales

Esencial Estos son los mensajes clave:

  • Límites de tarifa frenan los ataques maliciosos y protegen los recursos de backend.
  • Ráfaga/sin retardo detectan los picos legítimos sin bloquear a los usuarios.
  • zonas distinguir entre personas y bots con límites diferentes.
  • Registro proporciona datos para refinar los límites de forma iterativa.
  • Integración Con WAF, protección contra DDoS y supervisión, se potencia su eficacia.

Por qué la limitación de tasa detiene los ataques de forma temprana

Los atacantes apuestan por un alto Frecuencia de solicitudes, para hacer un uso indebido de los formularios de inicio de sesión, sobrecargar las API o extraer contenidos de forma automatizada. Por eso limito las solicitudes por clave —normalmente por IP— y decido si las limito, las retraso o respondo con un código 429. De este modo, mantengo el tráfico de bots alejado de la CPU, la base de datos y la lógica de la aplicación, y dejo pasar a los usuarios legítimos. Las rutas especialmente sensibles, como /login, /auth, /xmlrpc.php o las búsquedas que consumen muchos recursos, se benefician enormemente de ello. La fuente de este procedimiento es la Documentación de Nginx sobre el módulo ngx_http_limit_req_module.

Funcionamiento del módulo NGINX en la práctica

El módulo funciona según el Cubo con fugasPrincipio: Para cada clave, NGINX almacena los valores de contador en una zona y los compara con la tasa permitida. Las claves típicas son $binary_remote_addr para direcciones IP, tokens para claves de API o valores derivados mediante «map». Si un cliente supera de forma persistente la tasa y el búfer de picos, NGINX rechaza la solicitud antes de que llegue al backend. Esto ahorra tiempo de procesamiento y reduce la latencia para los visitantes reales. Configuro la respuesta con el código de estado 429 «Too Many Requests» o, si se prefiere, con otro Código de estado um.

Configuración: explicación paso a paso

Empiezo con una zona en la sección http, establezco una tasa moderada y la activo de forma selectiva en rutas sensibles. Para picos de corta duración, defino un «burst», opcionalmente con «nodelay», para evitar rechazos bruscos. A continuación, realizo pruebas en el entorno de staging y analizo los registros antes de activarlo en producción. De este modo, evito bloqueos innecesarios para los usuarios reales. Un ejemplo conciso ilustra el Sintaxis tangible:

# http {}
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;

server {
  location /api/ {
    limit_req zone=req_limit_per_ip burst=20 nodelay;
    limit_req_status 429;
  }

  location /login {
    limit_req zone=req_limit_per_ip burst=5;
    limit_req_status 429;
  }
}

Protección contra bots con zonas y lógica de agente de usuario

Los límites basados en direcciones IP rara vez son suficientes contra las redes de bots distribuidas, por lo que separo el tráfico en zonas: A las personas se les asignan valores más generosos, mientras que a los rastreadores genéricos se les aplican límites más estrictos. Con «map» evalúo los agentes de usuario, identifico a los bots exentos, como Googlebot, y les asigno límites propios que superviso de cerca. Para los rastreadores desconocidos, establezco límites estrictos en rutas costosas. Si detecto patrones, aumento el rigor de forma dinámica hasta que la Tarifa vuelve a estar dentro de los límites normales.

Ajuste fino: velocidad de transmisión, ráfaga, sin retardo y códigos de estado

La tasa regula el rendimiento por segundo, el «burst» permite búferes de corta duración y «nodelay» determina si prefiero el búfer o el paso inmediato. Empiezo con un valor moderado, por ejemplo, 10 r/s con «burst» 20 en las API, y lo ajusto tras analizar los registros. Para las rutas de inicio de sesión, por ejemplo, establezco 1 r/s con un «burst» pequeño para frenar los ataques de fuerza bruta. En caso de que se superen los límites, devuelvo un 429, ya que los clientes, con ello, arreglárselas y la lógica de reintento funciona correctamente. En casos especiales, utilizo códigos alternativos cuando los clientes lo solicitan.

Resumen en la tabla: directivas y aplicación

Los siguientes Cuadro resume las directrices fundamentales y explica en qué casos resulta conveniente aplicarlas.

directiva Efecto Ejemplo Uso típico
limit_req_zone Especifica la clave, la zona y Tarifa firme limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s; Base por IP, token o agente de usuario
limit_req Activa el límite en Ubicación/Servidor limit_req zone=perip burst=20 nodelay; Control preciso por ruta o vHost
limit_req_status Establece el código HTTP en Exceso limit_req_status 429; Comportamiento correcto del cliente y reintentos
mapa Redirige las solicitudes a zonas en map $http_user_agent $is_bot {…} Distinción entre bots y usuarios humanos según el User-Agent

Aplicación práctica: proteger de forma específica el punto final de inicio de sesión

Limito el acceso a /login de forma muy estricta, porque los bots prueban contraseñas con un alto Frecuencia Probar diferentes opciones. 1 r/s con «burst 3» evita los intentos masivos de adivinar la contraseña sin afectar demasiado a los usuarios reales. Además, registro los intentos fallidos repetidos en el log para bloquear temporalmente las direcciones IP. En combinación con la autenticación de dos factores (2FA) y, opcionalmente, el captcha, la carga sobre la base de datos y la gestión de sesiones se reduce notablemente. De esta forma, mantengo a raya los intentos fallidos y garantizo la Acceso a listo y estable.

En la práctica: ofrecer las API de forma justa y controlada

Las API requieren unas Probabilidades, para que los clientes individuales no acaparen todo el ancho de banda. Para las rutas generales, establezco 10 r/s y un pico de 20; para los puntos finales más costosos, aplico valores más estrictos. Si hay tokens o claves API disponibles, limito por token en lugar de por IP. Esto garantiza la equidad entre los clientes y evita los abusos. Para una explicación más detallada, consulta mi nota sobre Limitación de la frecuencia de las llamadas a la API, que ofrece una visión más amplia del concepto.

Seguimiento, registro y ajuste iterativo

Registro 429 respuestas, incluidas Clave (por ejemplo, IP o token) y la ruta, para detectar patrones. Los picos en unas pocas rutas indican scraping o ataques de fuerza bruta; una presión distribuida apunta a redes de bots. Con estos datos, establezco límites solo donde es necesario y minimizo los falsos positivos. Los paneles de control con tasas, índice de errores y latencia me muestran el efecto de cada cambio. De este modo, la Actuación alta, mientras que la protección aumenta.

Integración en un concepto de protección integral

Considero que la limitación de la tasa es un primer paso importante capa, pero lo combino con reglas WAF, reputación de IP y refuerzo de TLS. Contra los ataques de gran volumen, resulta útil una protección DDoS previa que filtre el tráfico a nivel de red antes de que NGINX tenga que intervenir. Mido continuamente las métricas, configuro alertas ante picos inusuales y reacciono actualizando las reglas. De este modo, a partir de varios componentes se crea una red de protección resistente. Estos artículos ofrecen una visión general práctica: Estrategias contra los ataques DDoS.

Patrones de configuración concretos para bots frente a personas

Clasifico a los visitantes en categorías con «map» y los dirijo a sus respectivas zonas. A los rastreadores conocidos les aplico límites moderados, mientras que a los agentes genéricos les impongo límites más estrictos. En el caso de rutas como /search o /report, soy más estricto, ya que consumen muchos recursos de la CPU. En caso de infracciones recurrentes, no aumento los límites, sino que aplico bloqueos temporales o traspaso la comprobación a un módulo de detección de bots. De este modo, la Índice de uso indebido bajo, sin interferir en el funcionamiento de los motores de búsqueda.

Ejemplo: dos zonas y asignación de agentes de usuario

El siguiente fragmento muestra la separación según Agente de usuario y la asignación de límites adecuados. Lo combino con códigos de estado diferenciados y campos de registro para medir el efecto con precisión. Los bots con un agente genérico pasan a la zona estricta. Las personas o los rastreadores verificados acceden a la zona más flexible. Este enfoque permite planificar Rendimientos por clase:

map $http_user_agent $is_bot {
  default 0;
  "~*googlebot"     0;
  "~*bingbot" 0;
  "~*crawler|scraper|bot" 1;
}

limit_req_zone $binary_remote_addr zone=human:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=bot:10m   rate=1r/s;

server {
  location / {
    if ($is_bot) {
 limit_req zone=bot burst=5;
    }
    if ($is_bot = 0) {
 limit_req zone=human burst=20 nodelay;
    }
    limit_req_status 429;
  }
}

Gestión de errores: comunicar correctamente el error 429

En Limits ofrezco una clara Respuesta indicando cuándo conviene volver a intentarlo. En el caso de las API, esto incluye el encabezado «Retry-After» válido, para que los clientes apliquen la estrategia de retroceso. Los usuarios humanos reciben una breve explicación sin detalles técnicos. Esto reduce el número de incidencias y garantiza un comportamiento comprensible. Una solución clara UX Hace que los límites resulten aceptables y evita la frustración.

Proveedor de alojamiento, red y kernel: reforzar las bases

Un elevado volumen de tráfico legítimo y las medidas de protección exigen soluciones fiables Recursos y unos valores predeterminados adecuados a nivel de red. Me aseguro de utilizar versiones actuales de NGINX, suficiente RAM para las zonas y funciones de protección contra ataques de transporte. Para protegerse contra las inundaciones SYN, resulta útil activar Cookies TCP SYN en el kernel, para que las conexiones no se atasquen. En definitiva, esto libera a NGINX de una carga innecesaria. De este modo, centro los límites en las capas HTTP y mantengo el Rendimiento estable.

En resumen: así es como utilizo eficazmente la limitación de tráfico de NGINX

Limito las solicitudes a clave, aíslo las rutas críticas y mantengo a raya a los bots mediante zonas de acceso restringido. Las funciones «Burst» y «nodelay» ayudan a permitir picos legítimos sin fomentar los abusos. A través de los registros 429, calibro los valores de forma continua y solo aumento los límites cuando es necesario. En combinación con el WAF, la defensa contra DDoS, la monitorización y el endurecimiento del kernel, se crea un concepto de protección robusto. Quien lo aplique de forma sistemática reducirá considerablemente el tráfico de bots y preservará Actuación incluso bajo carga.

Elementos que suelen faltar en la práctica

En muchas configuraciones faltan algunos componentes clave que aumentan notablemente la eficacia de la limitación de velocidad:

  • IP real del cliente detrás de los proxies: Si no se gestiona correctamente la IP real, NGINX suele limitar la IP del equilibrador de carga, con lo que los límites se aplican a todos los usuarios agrupados detrás de él.
  • Pruebas en seco (Dry-Run): Los límites se activan „a ciegas“. Es mejor registrar de antemano solo la frecuencia con la que se habría aplicado un límite.
  • Claves de grano fino: En lugar de limitar solo por dirección IP, conviene establecer límites por token de API, sesión o usuario para garantizar una mayor equidad.
  • Interacción con limit_conn: Las conexiones paralelas y las tasas de solicitudes abarcan diferentes patrones de uso indebido.
  • Excepciones específicas: Las comprobaciones de estado, los webhooks o los servicios internos suelen necesitar límites más flexibles o ningún límite.

Proxy inverso: evaluar de forma segura la IP real del cliente

Si NGINX está detrás de un equilibrador de carga, configuro las directivas de IP real para que $binary_remote_addr refleje la dirección real del cliente. Solo confío en las redes que me pertenecen y activo la evaluación recursiva:

http {
  # Rangos de IP de proxy de confianza (ejemplo)
  set_real_ip_from 10.0.0.0/8;
  set_real_ip_from 192.168.0.0/16;
  #: añadir rangos públicos de LB/CDN si es necesario

  real_ip_header X-Forwarded-For;
  real_ip_recursive on;

  limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
}

Sin esta configuración, un límite afectaría de forma injustificada a muchos usuarios a la vez. Tras la configuración, compruebo en los registros de acceso si aparece la IP del cliente esperada.

Estrategia clave: IP, usuario, token y ruta

La clave elegida determina la equidad y la eficacia. Algunos modelos que han demostrado su eficacia:

  • Pro IP ($binary_remote_addr): Listo para usar rápidamente, ideal para /login y puntos finales anónimos.
  • Por cada token de API: Equidad entre los clientes; protege contra la agrupación NAT. Extraigo los tokens mediante map.
  • Por clase de ruta: Limitar por separado los puntos finales más costosos, por ejemplo, /search más que /status.
map $http_authorization $api_token {
  default "";
  "~*^Bearer\s+(.+)$" $1;
}

limit_req_zone $api_token zone=per_token:30m rate=5r/s;

server {
  location /api/ {
    # Solo es relevante si hay un token disponible
    limit_req zone=per_token burst=10;
    limit_req_status 429;
  }
}

Importante: una cardinalidad elevada de las claves consume memoria en la zona. Prevé un margen de memoria y supervisa el uso de memoria.

Acumuladores y dimensionamiento de las zonas

La zona almacena metadatos por cada clave activa. El consumo por entrada es de unas cuantas docenas de bytes, más la sobrecarga. De ahí deduzco que:

  • Para un gran número de direcciones IP o tokens simultáneos, elijo zonas más grandes, por ejemplo, de 50 a 100 MB.
  • Empiezo con una configuración bastante generosa y reviso los registros de NGINX: el mensaje „shared memory zone is full“ indica que hay que ajustar la configuración.
  • Las claves no utilizadas caducan tras un breve periodo de inactividad; los picos son más importantes que la media diaria.

Utilizar «Burst» y «nodelay» con precisión

Sin sin retardo NGINX agrupa los excesos dentro del búfer de ráfagas y retrasado Solicitudes. Con sin retardo Las solicitudes en ráfaga válidas se admiten de inmediato, mientras que las excedentes se rechazan. Mi procedimiento:

  • Recorridos interactivos (HTML): más bien sin «nodelay», para generar tiempos de espera breves en lugar de errores 429 definitivos.
  • APIs: a menudo con «nodelay», para que los clientes reciban claramente el código de error 429 y apliquen el backoff.
  • Terminales costosas: una pequeña ráfaga para suavizar los picos del backend.

Simulación, nivel de registro y evaluación

Antes de aplicar los límites, activo la función «Dry-Run» y ajusto el nivel de registro. Así puedo ver el efecto sin correr ningún riesgo:

server {
  location /api/ {
    limit_req zone=perip burst=20;
    limit_req_dry_run on; #: solo registrar, no bloquear
    limit_req_log_level notice;  #: menos grave que 'error'
  }
}

A continuación, analizo los datos de acceso de los últimos 3 a 7 días, identifico los puntos críticos, ajusto la tasa y el ráfaga y, solo entonces, desactivo el «dry-run».

429: cómo gestionarlo correctamente: HTML, JSON y Retry-After

Para garantizar una buena experiencia de usuario (UX), distingo entre navegadores y clientes de API, y utilizo Retry‑After. Así es como comunico los límites con claridad:

map $http_accept $wants_json {
  default 0;
  "~*application/json|/json"    1;
}

server {
  error_page 429 = @rate_limited;

  location @rate_limited {
    add_header Retry-After 2 always;
    if ($wants_json) {
 add_header Content-Type application/json;
      return 429 '{"error":"too_many_requests","retry_after":2}';
    }
    return 429 "Inténtalo de nuevo más tarde.";
  }
}

De este modo, las API pueden reaccionar de forma programática y los usuarios reciben un mensaje claro.

Combinar limit_req y limit_conn

limit_req rendimiento por intervalo de tiempo, limit_conn limita las conexiones simultáneas. Para evitar descargas, clientes que envían muchos mensajes o avalanchas de HTTP/2, combino ambas opciones:

limit_conn_zone $binary_remote_addr zone=perip_conn:10m;

server {
  location /api/ {
    limit_req  zone=perip burst=20 nodelay;
    limit_conn zone=perip_conn 20;  # máximo de 20 conexiones simultáneas por IP
  }
}

De esta forma evito que unos pocos clientes, aunque respeten la velocidad, acaparen recursos con demasiadas conexiones simultáneas.

Excepciones, comprobaciones de estado y rutas internas

No todas las rutas necesitan límites. Las comprobaciones de estado (/healthz), los webhooks internos o las devoluciones de llamada de pago tienen sus propias ubicaciones sin `limit_req`, o con valores más moderados:

server {
  # sin límites para las comprobaciones de estado
  location = /healthz { return 200 "ok"; }

  # límites flexibles para las respuestas de pago
  location /webhooks/pay/ {
    limit_req zone=perip burst=5;
  }

  # Protección estricta para el inicio de sesión
  location = /login {
    limit_req zone=perip rate=1r/s burst=3;
  }
}

Las excepciones granulares reducen los falsos positivos y mantienen la estabilidad de las integraciones.

Enrutamiento por zonas más robusto sin «magia» de If

Para la separación entre „bot“ y «persona», prefiero las redirecciones internas mediante ubicaciones con nombre. Esto hace que la configuración sea clara y predecible:

map $http_user_agent $is_bot {
  default 0;
  "~*googlebot|bingbot" 0;
  "~*crawler|scraper|bot" 1;
}

limit_req_zone $binary_remote_addr zone=human:20m rate=10r/s;
limit_req_zone $binary_remote_addr zone=bot:10m   rate=1r/s;

server {
  error_page 418 = @bot;

  location / {
    if ($is_bot) { return 418; }   # redirección interna
    limit_req zone=human burst=20 nodelay;
    limit_req_status 429;
    try_files $uri $uri/ /index.html;
  }

  location @bot {
    limit_req zone=bot burst=5;
    limit_req_status 429;
  }
}

Así, los bots acaban de forma determinista en la zona estricta, mientras que las personas lo hacen en la relajada, sin que ambos límites se apliquen al mismo tiempo.

Probar, medir, ponerse la ropa: un proceso práctico

  • Puesta en escena: Seleccionar una tasa/ráfaga conservadora, activar Dry-Run y ejecutar la carga sintética contra la ruta crítica.
  • Pruebas de humo: Generar ráfagas cortas con curl o Lasttools y comprobar el comportamiento del código 429 y el retraso.
  • Programa piloto de producción: Aplicarlo primero en ubicaciones concretas y realizar un seguimiento exhaustivo de los registros.
  • Afilado iterativo: Establecer límites solo allí donde se detecten patrones; minimizar las falsas alarmas.
Ejemplo de #: prueba de ráfaga rápida con curl
for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/login & done; wait

Frecuencias en minutos en lugar de segundos y rutas granulares

NGINX permite establecer intervalos en segundos o minutos (r/s, r/m). En caso de uso indebido de inicio de sesión, suelo establecer 60r/m en lugar de 1r/s, para permitir dobles clics legítimos breves, pero limitar los clics continuos. Las rutas más caras tienen límites más estrictos que las baratas. Ejemplo:

limit_req_zone $binary_remote_addr zone=perip_min:20m rate=60r/m;

server {
  location /search/ {
    limit_req zone=perip_min burst=10;   # más estricto
  }
  location /status {
    # sin límite: económico y de uso interno
    return 200;
  }
}

Los escollos y cómo los evito

  • Llave equivocada: Detrás de los servidores proxy sin IP real, sin querer, estoy limitando el acceso a todos los usuarios a la vez.
  • Zonas demasiado pequeñas: El mensaje „zone is full“ provoca un comportamiento impredecible; por lo tanto, hay que dimensionar con holgura.
  • Un límite para todo: Cada trayectoria requiere valores distintos; una solución única para todos genera frustración.
  • Sin control: Sin el análisis 429, las configuraciones erróneas pasan desapercibidas.
  • Lista blanca ampliada: Las excepciones demasiado amplias abren la puerta a todo tipo de abusos; hay que crear listas blancas de forma selectiva, temporal y transparente.

Características especiales de HTTP/2, SSE y el almacenamiento en caché

HTTP/2 agrupa las solicitudes en unas pocas conexiones; limit_conn sigue siendo relevante, ya que las transmisiones consumen recursos. Los eventos enviados por el servidor (Server-Sent Events) o las descargas largas rara vez activan los límites de velocidad (pocas solicitudes), pero consumen tiempo; en estos casos, aplico límites en paralelo con `limit_conn` o implemento estrategias de ancho de banda. Siempre que sea posible, aligero la carga con Almacenamiento en caché (por ejemplo, recursos estáticos, solicitudes GET frecuentes), para que los límites se apliquen con menos frecuencia y los usuarios obtengan respuestas más rápidas.

Lista de comprobación operativa

  • La dirección IP real es correcta, las claves están definidas (IP/token/usuario)
  • Zonas de generosas dimensiones, métricas y registros disponibles
  • velocidad/ráfaga ajustada por clase de ruta, «nodelay» establecido deliberadamente
  • Se ha probado el «dry run» y se ha implementado la comunicación 429 (Retry-After)
  • Excepciones para Health/Webhooks, combinación con limit_conn
  • Reajuste iterativo y alertas ante anomalías

Artículos de actualidad