abuse-guard: Auto-prohibir clientes abusivos por tasa de respuestas de error (404/403/5xx)
Requiere el plan Pro (o superior) de la suscripción de NGINX Extras de GetPageSpeed.
Instalación
Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:
- RedHat Enterprise Linux 7, 8, 9 y 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 y Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-abuse-guard
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-abuse-guard
Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:
load_module modules/ngx_http_abuse_guard_module.so;
Este documento describe nginx-module-abuse-guard v1.1.0 lanzado el 09 de julio de 2026.
Tu registro de errores es una confesión. Abuse Guard lo lee en tiempo real y cierra la puerta a los abusadores.
Cada escáner, fuzzer y bot de relleno de credenciales deja la misma huella:
una lluvia de 404s buscando rutas ocultas, 403s golpeando puertas cerradas, solicitud
fallida tras solicitud fallida. Abuse Guard observa los códigos de estado que tu servidor
realmente devuelve, identifica a los clientes cuyo tráfico es mayormente fallido y
los bloquea — decidido dentro del trabajador de NGINX, en la solicitud misma, en unos
pocos microsegundos. Sin sidecar. Sin transportador de registros. Sin capa de scripting. Solo C
compilado haciendo un trabajo excepcionalmente bien.
Hoja de especificaciones
| Disparador | Tasa de respuestas de error por cliente que eliges (403/404 por defecto) |
| Acción | Bloqueo temporal — una prohibición dura por un tiempo fijo, no una limitación |
| Punto de decisión | Fase de preacceso de NGINX, antes de que se ejecute cualquier manejador o upstream |
| Modelo de memoria | Bytes fijos por cliente, independiente del umbral → escala de botnet |
| Modo de flota | Replicación de prohibiciones opcional entre nodos a través de Redis / Valkey |
| Durabilidad | Instantáneas de prohibición opcionales en disco que sobreviven a recargas y reinicios |
| Huella | Un módulo autónomo; cero dependencias en tiempo de ejecución por defecto |
| Plataformas | RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux |
El problema que elimina
Los visitantes legítimos casi nunca generan una explosión de errores. Los abusadores generan
poco más — esa asimetría es todo el juego. Un escáner de vulnerabilidades caminando
por tu árbol es una pared de 404s. Un bot sondeando puntos finales de administrador es una pared de 403s.
Una ejecución de fuerza bruta es una pared de fallos.
Los limitadores de tasa tratan ese tráfico como cualquier otro: ralentizan a todos por volumen de solicitud y dejan que el infractor vuelva a entrar en el instante en que se afloja. Abuse Guard hace lo contrario. Ignora completamente el tráfico bien comportado y reserva su única respuesta — una prohibición real y limitada en el tiempo — para clientes definidos por sus errores.
Usa un limitador de tasa para dar forma a la carga. Usa Abuse Guard para desalojar abusos.
Cómo se decide una prohibición
Tres partes móviles, todas dentro del trabajador:
1 · Una puntuación filtrante, por cliente. Cada identidad de cliente lleva un solo número pequeño
en memoria compartida. Cada error que coincide añade a ella; la puntuación se desangra
continuamente a umbral ÷ intervalo por segundo. Un estallido corto y agudo la empuja
más allá de la línea; un goteo lento nunca lo hace. Crucialmente, esa puntuación es un registro de tamaño fijo
sin importar cuán alto establezcas el umbral — así que una sola zona rastrea cómodamente
las decenas de miles de direcciones de origen distintas que una botnet te lanza.
2 · Un plazo duro. En el momento en que la puntuación cruza tu umbral, el cliente
gana un timestamp bloqueado_hasta. Hasta entonces simplemente está ausente — cada solicitud
es rechazada en la fase de preacceso, antes de que NGINX gaste un ciclo en enrutamiento,
archivos o upstreams. El rechazo es el resultado más barato posible.
3 · Un rechazo correcto en términos de privacidad. Los clientes prohibidos reciben 429 Too Many Requests
(código de tu elección) etiquetado para que ninguna caché compartida pueda almacenarlo y servir la
penalización de un cliente a otro, con un Retry-After indicando a los clientes honestos cuándo
regresar.
Las identidades se pliegan en un resumen de tamaño fijo, por lo que clavear algo voluminoso como
$request_uri o un encabezado cuesta exactamente la misma cantidad de memoria que clavear una IP.
Vive en menos de un minuto
Abuse Guard se envía como un módulo precompilado y firmado desde el repositorio de GetPageSpeed — simplemente colócalo, no se requiere herramienta de construcción.
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard
Conéctalo:
load_module modules/ngx_http_abuse_guard_module.so;
http {
abuse_guard_zone zone=clients:10m; # una zona de memoria compartida
server {
location / {
abuse_guard zone=clients; # hacer cumplir aquí
}
}
}
sudo nginx -t && sudo systemctl reload nginx
Esos valores predeterminados prohíben cualquier IP que devuelva 100 403/404 respuestas dentro de un
intervalo de 5 minutos, durante una hora. Ajusta o relaja cada número a continuación.
Configuración
Abuse Guard tiene cuatro directivas. La primera declara una política; las demás la aplican, eximen a personas de ella y (opcionalmente) la comparten entre máquinas.
Declara una política — abuse_guard_zone
Una directiva a nivel http. Crea una zona de memoria compartida y establece la
política que la rige. Establece tantos o tan pocos controles como desees: el nombre y el tamaño de la
zona son lo único que debes proporcionar; valores predeterminados sensatos completan el resto (los valores
que se muestran a continuación son exactamente esos valores predeterminados).
abuse_guard_zone zone=clients:10m ← nombre + tamaño (lo único imprescindible)
key=$binary_remote_addr ← quién es "un cliente"
statuses=403,404 ← qué respuestas cuentan como errores
interval=300s ← la ventana de puntuación
threshold=100 ← errores en esa ventana → prohibir
block=60m; ← cuánto tiempo dura la prohibición
zone=clients:10m es la identidad y el presupuesto de la política: un nombre que referencias
desde abuse_guard, y el tamaño de la memoria compartida. Aproximadamente 10 MB rastrean del orden de
cien mil clientes activos.
Todo lo demás es ajuste opcional:
key— la expresión que define un solo cliente. Cualquier variable de NGINX; el valor predeterminado$binary_remote_addrclavea en la IP de origen. Una solicitud cuyo clave salga vacía se omite por completo (útil con unmap, a continuación).statuses— los códigos de respuesta que cuentan como errores: códigos individuales, rangos, o una mezcla, por ejemplostatuses=401,403,404,500-599. Por defecto es403,404.interval— la ventana en la que la puntuación se descompone (por defecto300s). Un estallido dentro de ella activa una prohibición; un goteo lento extendido nunca acumula.threshold— cuántos errores dentro de esa ventana cruzan la línea, hasta 1024 (por defecto100).block— cuánto tiempo un cliente activado permanece bloqueado (por defecto60m).inactive— cuánto tiempo un cliente inactivo permanece en memoria antes de ser reclamado (por defectomax(1h, interval, block); cualquier valor explícito debe ser al menos tan grande comointervalyblock).redis—onpara replicar las prohibiciones de esta zona a través de una flota (ver abajo);offpor defecto.persist— una ruta de archivo para almacenar instantáneas de prohibiciones para que sobrevivan a un reinicio.persist_interval— con qué frecuencia se reescribe esa instantánea (por defecto5s).persist_secret— una clave hexadecimal que firma la instantánea con HMAC-SHA256, de modo que un archivo manipulado sea rechazado en lugar de cargado.
Por qué se omite
5xxpor defecto: un error del servidor es generalmente culpa de tu lado, y contarlo permitiría que un backend inestable hiciera que visitantes inocentes fueran prohibidos. Añadestatuses=403,404,500-599solo cuando desees actuar deliberadamente sobre clientes que desencadenan errores del servidor.
Aplícalo — abuse_guard
Válido en bloques http, server y location, por lo que puedes proteger todo un sitio
o solo los puntos finales que atraen abusos. Nombra la zona para activarla; escribe
abuse_guard off; en un ámbito anidado para desactivarla nuevamente.
location /wp-login.php {
abuse_guard zone=clients status=429 log_level=warn;
}
zone— la zona (declarada arriba) cuya política se aplica aquí.status— el código que recibe un cliente prohibido, en cualquier lugar de400–599(por defecto429).dry_run—onpara observar sin hacer cumplir: el veredicto se registra pero no se escribe ninguna prohibición. Apagado por defecto.log_level— cuán ruidosamente registrar cada decisión:info,notice(por defecto),warnoerror.
Despliega sin miedo con dry_run=on. Registra cada prohibición que emitiría
sin tocar el estado, para que puedas calibrar umbrales contra tráfico en vivo — incluso
junto a una ubicación que esté haciendo cumplir en la misma zona — y luego activarlo en vivo.
Exime a los buenos — abuse_guard_allow
Contexto: http · server · location · repetible, heredado hacia abajo.
abuse_guard_allow 127.0.0.0/8;
abuse_guard_allow 10.0.0.0/8 192.168.0.0/16;
Los clientes listados nunca son contados y nunca son prohibidos. La coincidencia se realiza en la verdadera
dirección de conexión, por lo que coopera con realip. Así es como proteges a raspadores de búsqueda verificados: permite los rangos publicados de Googlebot / Bingbot para que un
bot que atraviesa URLs obsoletas (y acumulando 404s) nunca sea atrapado.
Comparte prohibiciones a través de la flota — abuse_guard_redis
Contexto: http
abuse_guard_redis host=10.0.0.5 password=… ; # tls://host para TLS
abuse_guard_zone zone=clients:10m redis=on;
Apunta cada nodo a un Redis o Valkey, activa redis=on, y una prohibición ganada en cualquier
máquina se propaga a todas ellas. Valores predeterminados: port=6379, db=0, prefix=ag_,
timeout=100ms. Cómo se mantiene rápido es la siguiente sección.
SELinux: en sistemas de aplicación (RHEL, Rocky, AlmaLinux) el kernel impide que NGINX
abra la conexión a Redis hasta que lo permitas una vez —
setsebool -P httpd_can_network_connect 1. Si omites esto, la replicación no hará nada silenciosamente
mientras la aplicación local continúa como de costumbre.
Una prohibición, cada nodo — sin ralentizar una sola solicitud
Detrás de un balanceador de carga, una prohibición por servidor es teatro: el atacante simplemente aterriza en un nodo diferente. Abuse Guard cierra esa brecha sin poner nunca a Redis en el camino de la solicitud.
Cada nodo decide localmente y cuenta localmente. En el instante en que emite una prohibición, difunde ese único hecho al clúster y registra una copia duradera. Cada otro nodo lo importa en milisegundos, y cualquier nodo que estuvo fuera de línea se reconcilia en el momento en que se reconecta. Debido a que la aplicación siempre se sirve desde el estado en memoria de cada nodo, la solicitud de un visitante nunca espera un viaje de red — el único costo de la agrupación es que un atacante recién prohibido se queda fuera de la flota un latido después en lugar de instantáneamente.
Redis aquí es una campana de alarma unidireccional, no un libro mayor compartido consultado por cada solicitud — así que un Redis lento o ausente nunca puede añadir latencia a tu tráfico. Ejecútalo en una red privada y trátalo como privilegiado: cualquier cosa que pueda escribir en él puede emitir prohibiciones.
Prohibiciones que sobreviven a un reinicio
Apunta una zona a un archivo y las prohibiciones activas se almacenan en instantáneas en un intervalo y se restauran al inicio, de modo que una recarga o un reinicio no le dé a cada atacante una pizarra fresca.
abuse_guard_zone zone=clients:10m
persist=/var/lib/nginx/abuse_guard/clients.state
persist_secret=00112233445566778899aabbccddeeff;
La instantánea se verifica en integridad, se escribe para que un fallo nunca deje un archivo roto,
y — con persist_secret — se firma criptográficamente para que un archivo manipulado sea
rechazado en lugar de confiado. Mantén el directorio legible solo por el usuario del trabajador.
Ve todo lo que decide
Tres variables exponen el veredicto de Abuse Guard a tus registros y configuración:
| Variable | Valor |
|---|---|
$abuse_guard_status |
BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN |
$abuse_guard_count |
Errores actualmente atribuidos a este cliente. |
$abuse_guard_blocked_until |
Tiempo Unix en que se levanta la prohibición, o 0. |
log_format guard '$remote_addr "$request" $status '
'guard=$abuse_guard_status count=$abuse_guard_count';
¿Claveando detrás de un CDN o proxy? Nunca confíes en un X-Forwarded-For crudo. Deja que
realip resuelva primero el cliente real, luego clavea en $binary_remote_addr:
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
¿Necesitas lógica de exención por solicitud? Cualquier solicitud cuyo key resuelva a una cadena vacía es ignorada — así que un map te permite, por ejemplo, rastrear visitantes anónimos por IP mientras
dejas a los usuarios autenticados sin tocar.
Diseñado para ser confiable en producción
Abuse Guard se mantiene a un estándar muy por encima de "compila." Cada cambio pasa por el gauntlet de AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, análisis estático y fuzzing continuo de sus analizadores y formato en disco. Sus dependencias opcionales — agrupación y instantáneas firmadas — son de mejor esfuerzo por diseño: si Redis o el disco se comportan mal, la aplicación continúa silenciosamente desde la memoria local. Tu tráfico nunca se mantiene como rehén de una dependencia.
Obtén Abuse Guard
Abuse Guard es un módulo comercial de NGINX de GetPageSpeed LLC, entregado con actualizaciones y soporte continuos a través de una suscripción de GetPageSpeed.
- Navega por el catálogo completo de módulos de NGINX → https://nginx-extras.getpagespeed.com/modules/
- Licencias, implementaciones a gran escala, o ayuda para configurarlo → getpagespeed.com/contact-us
© GetPageSpeed LLC. Todos los derechos reservados.