abuse-guard: Bloqueo automático de clientes abusivos según la tasa de respuestas de error
Instalación
Puede instalar este módulo en cualquier distribución basada en RHEL, incluyendo, entre otras:
- 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
Habilite el módulo añadiendo lo siguiente al principio de /etc/nginx/nginx.conf:
load_module modules/ngx_http_abuse_guard_module.so;
Este documento describe nginx-module-abuse-guard v2.1.0 publicado el 3 de septiembre de 2026.
Su registro de errores es una confesión. Abuse Guard lo lee en tiempo real y expulsa a los abusadores.
Cada escáner, fuzzer y bot de relleno de credenciales deja la misma huella:
una ráfaga de 404s buscando rutas ocultas, 403s probando puertas cerradas,
solicitud fallida tras solicitud fallida. Abuse Guard observa los códigos de estado que su servidor
realmente devuelve, identifica a los clientes cuyo tráfico es mayoritariamente fallido y
los bloquea — decidido dentro del worker de NGINX, sobre la propia solicitud, en unos pocos
microsegundos. Sin sidecar. Sin log shipper. Sin capa de scripting. Solo C compilado
haciendo un trabajo excepcionalmente bien.
Ficha técnica
| Disparador | Tasa por cliente de respuestas de error que usted elija (403/404 por defecto) |
| Acción | Bloqueo temporal — una prohibición firme durante una ventana fija, no una limitación |
| Punto de decisión | Fase de preacceso de NGINX, antes de que se ejecute cualquier handler o upstream |
| Modelo de memoria | Bytes fijos por cliente, independiente del umbral → escala a nivel de botnet |
| Modo flota | Replicación opcional de prohibiciones entre nodos mediante Redis / Valkey |
| Durabilidad | Instantáneas de salida opcionales que conservan las prohibiciones activas entre reinicios |
| Huella | Un módulo autocontenido; 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 ráfaga de errores. Los abusadores generan
poco más que eso — esa asimetría es todo el juego. Un escáner de vulnerabilidades que recorre
su árbol es un muro de 404s. Un bot probando endpoints de administración es un muro de 403s.
Un ataque de fuerza bruta es un muro de fallos.
Los limitadores de tasa tratan ese tráfico como cualquier otro: ralentizan a todos por volumen de solicitudes y dejan que el infractor vuelva a entrar en el mismo instante en que se calma. Abuse Guard hace lo contrario. Ignora por completo 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.
Use un limitador de tasa para modelar la carga. Use Abuse Guard para expulsar el abuso.
Cómo se decide una prohibición
Tres piezas móviles, todas dentro del worker:
1 · Una puntuación con fuga, por cliente. Cada identidad de cliente lleva un único número
pequeño en memoria compartida. Cada error que coincide añade un punto por defecto, o el
peso que usted asigne a ese estado; la puntuación se desvanece continuamente a
umbral ÷ intervalo por segundo. Una ráfaga corta y aguda la empuja por encima del límite;
un goteo lento nunca lo consigue. Fundamentalmente, esa puntuación es un único registro de tamaño fijo sin
importar lo alto que establezca el umbral, por lo que una sola zona rastrea cómodamente las
decenas de miles de direcciones de origen distintas que una botnet le lanza.
2 · Una fecha límite firme. En el momento en que la puntuación cruza su umbral, el cliente
obtiene una marca de tiempo blocked_until. Hasta entonces simplemente desaparece — 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 · Una negativa correcta en cuanto a privacidad. Los clientes bloqueados reciben 429 Too Many Requests
(el código que usted elija) etiquetado para que ninguna caché compartida pueda almacenarlo y servir el
castigo de un cliente a otro, con un Retry-After que indica a los clientes honestos cuándo
volver.
Las identidades se pliegan en un digest de tamaño fijo, por lo que usar como clave algo voluminoso como
$request_uri o una cabecera cuesta exactamente la misma memoria que usar una IP.
En funcionamiento en menos de un minuto
Abuse Guard se distribuye como un módulo precompilado y firmado desde el repositorio GetPageSpeed — instálelo, sin necesidad de toolchain de compilación.
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard
Conéctelo:
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; # aplicar aquí
}
}
}
sudo nginx -t && sudo systemctl reload nginx
Esos valores por defecto prohíben cualquier IP que devuelva 100 respuestas 403/404 en una
ventana de 5 minutos, durante una hora. Ajuste cada número a continuación.
Configuración
Abuse Guard son cuatro directivas. La primera declara una política; el resto la aplican, eximen a personas de ella y (opcionalmente) la comparten entre máquinas.
Declarar una política — abuse_guard_zone
Una directiva a nivel de http. Reserva una zona de memoria compartida y establece la
política que la gobierna. Configure tantos o tan pocos parámetros como desee — el
nombre y el tamaño de la zona son lo único que debe proporcionar; los valores por defecto sensatos completan
el resto (los valores mostrados a continuación son exactamente esos valores por defecto).
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 suman a la puntuación
interval=300s ← la ventana de puntuación
threshold=100 ← puntuación en esa ventana → prohibición
block=60m; ← cuánto dura la prohibición
zone=clients:10m es la identidad y el presupuesto de la política: un nombre al que hace
referencia abuse_guard, y el tamaño de la memoria compartida. Unos 10 MB rastrean del orden de
cien mil clientes activos.
Todo lo demás es ajuste opcional:
key— la expresión que define un único cliente. Cualquier variable de NGINX; el valor por defecto$binary_remote_addrusa como clave la IP de origen. Una solicitud cuya clave resulta vacía se omite por completo (útil con unmap, más abajo).statuses— las respuestas que suman a la puntuación. Un código o rango simple tiene peso 1, conservando la sintaxis original:statuses=403,404,500-599. Añada:weightpara que una respuesta consuma más del mismo presupuesto, por ejemplostatuses=404,401:5,500-599:2. Los pesos son enteros del 1 al 1024 y un rango aplica su peso a cada estado que cubre. Repetir o superponer un estado con el mismo peso es inofensivo; pesos conflictivos hacen fallarnginx -t. El valor por defecto sigue siendo403,404.interval— la ventana en la que la puntuación decae (por defecto300s). Una ráfaga dentro de ella activa una prohibición; un goteo lento distribuido en un periodo más amplio nunca se acumula.threshold— cuántos puntos de puntuación dentro de esa ventana cruzan el límite, hasta 1024 (por defecto100). Una respuesta pesada puede consumir el presupuesto restante y activar una prohibición inmediatamente.block— cuánto tiempo permanece bloqueado un cliente que ha activado la prohibición (por defecto60m).inactive— cuánto tiempo permanece un cliente inactivo en memoria antes de ser reclamado (por defectomax(1h, interval, block); cualquier valor explícito debe ser al menos tan grande como tantointervalcomoblock).redis—onpara replicar las prohibiciones de esta zona en una flota (ver más abajo);offpor defecto.persist— una ruta de archivo donde las prohibiciones activas se vuelcan en la salida limpia del worker y se cargan al inicio.persist_secret— en compilaciones con soporte de instantáneas firmadas, una clave hexadecimal que añade autenticación HMAC-SHA256 para que un archivo manipulado sea rechazado.
Por qué
5xxqueda excluido por defecto: un error de servidor suele ser culpa de su lado, y contarlo permitiría que un backend con fallos intermitentes consiguiera que visitantes inocentes fueran bloqueados. Añadastatuses=403,404,500-599solo cuando quiera deliberadamente actuar sobre clientes que provocan errores de servidor.
Aplicarla — abuse_guard
Válida en bloques http, server y location, por lo que puede proteger un sitio completo
o solo los endpoints que atraen abuso. Nombre la zona para activarla; escriba
abuse_guard off; en un ámbito anidado para desactivarla.
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 bloqueado, en cualquier lugar de400–599(por defecto429).dry_run—onpara observar sin aplicar: el veredicto se registra pero no se escribe ninguna prohibición. Desactivado por defecto.log_level— con qué nivel se registra cada decisión:info,notice(por defecto),warnoerror.
Despliegue sin miedo con dry_run=on. Registra cada prohibición que emitiría
sin tocar el estado, para que pueda calibrar los umbrales contra el tráfico real — incluso
junto a una location que aplica en la misma zona — y luego actívelo en producción.
Eximir 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 se cuentan ni se prohíben. La coincidencia se realiza sobre la
dirección de conexión real, por lo que coopera con realip. Esta es también la forma de proteger
rastreadores de búsqueda verificados: permita los rangos publicados de Googlebot / Bingbot para que un
bot que recorre URLs obsoletas (y acumulando 404s) nunca sea atrapado.
Compartir prohibiciones en 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;
Apunte cada nodo a un único Redis o Valkey, active redis=on, y una prohibición obtenida en cualquier
máquina se propaga a todas ellas. Valores por defecto: port=6379, db=0, prefix=ag_,
timeout=100ms. Cómo se mantiene rápido es la siguiente sección.
SELinux: en sistemas con enforcing (RHEL, Rocky, AlmaLinux) el kernel impide que NGINX
abra la conexión a Redis hasta que lo permita una vez —
setsebool -P httpd_can_network_connect 1. Si omite esto, la replicación
no hará nada silenciosamente mientras la aplicación local continúa con normalidad.
Una prohibición, cada nodo — sin ralentizar una sola solicitud
Detrás de un balanceador de carga, una prohibición por servidor es un teatro: el atacante simplemente aterriza en un nodo diferente. Abuse Guard cierra esa brecha sin poner nunca a Redis en la ruta de la solicitud.
Cada nodo decide localmente y cuenta localmente. En el instante en que emite una prohibición, transmite ese único hecho al clúster y registra una copia duradera. Cada otro nodo lo importa en milisegundos, y cualquier nodo que estaba sin conexión 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 ida y vuelta por la red — el único coste del agrupamiento es que un atacante recién prohibido queda excluido en toda la flota un latido después en lugar de instantáneamente.
Redis aquí es una campana de alarma unidireccional, no un libro de contabilidad compartido consultado por solicitud — por lo que un Redis lento o ausente nunca puede añadir latencia a su tráfico. Ejecútelo en una red privada y trátelo como privilegiado: cualquier cosa que pueda escribir en él puede emitir prohibiciones.
Prohibiciones que sobreviven a un reinicio
Apunte una zona a un archivo y las prohibiciones activas se vuelcan cuando el worker sale limpiamente, y luego se restauran al inicio. Las recargas y los reinicios ordenados mantienen las prohibiciones actuales sin ejecutar un escritor periódico de toda la zona. Un fallo abrupto del proceso o de la máquina puede perder prohibiciones emitidas desde la última salida limpia; la aplicación sigue fallando en abierto.
abuse_guard_zone zone=clients:10m
persist=/var/lib/nginx/abuse_guard/clients.state
persist_secret=00112233445566778899aabbccddeeff;
La instantánea compacta contiene solo digests de identidad y fechas límite de prohibición. CRC32
detecta corrupción, y un rename atómico mantiene las escrituras parciales fuera de la ruta
activa. Las compilaciones con soporte de instantáneas firmadas pueden además autenticarla con
persist_secret. Mantenga el directorio legible solo por el usuario del worker.
Vea todo lo que decide
Tres variables exponen el veredicto de Abuse Guard a sus registros y configuración:
| Variable | Valor |
|---|---|
$abuse_guard_status |
BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN |
$abuse_guard_count |
Puntuación ponderada actual, redondeada a un punto entero. |
$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';
¿Usando claves detrás de una CDN o proxy? Nunca confíe en un X-Forwarded-For crudo. Deje que
realip resuelva primero el cliente real, y luego use como clave $binary_remote_addr:
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
¿Necesita lógica de exención por solicitud? Cualquier solicitud cuya key se resuelva a una cadena
vacía se ignora — por lo que un map le permite, por ejemplo, rastrear visitantes anónimos por IP mientras
deja intactos a los usuarios autenticados.
Diseñado para ser confiable en producción
Abuse Guard se mantiene en un estándar muy por encima de "compila". Cada cambio pasa por el calvario de AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, análisis estático y fuzzing continuo de sus analizadores y formato en disco. Sus dependencias opcionales — agrupamiento e 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. Su tráfico nunca es rehén de una dependencia.
Obtenga Abuse Guard
Abuse Guard es un módulo comercial de NGINX de GetPageSpeed LLC, entregado con actualizaciones continuas y soporte a través de una suscripción a GetPageSpeed.
- Explore el catálogo completo de módulos NGINX → https://nginx-extras.getpagespeed.com/modules/
- Licencias, despliegues de volumen o ayuda para la configuración → getpagespeed.com/contact-us
© GetPageSpeed LLC. Todos los derechos reservados.