Saltar a contenido

ipset-access: Bloqueo de IPs con cero latencia usando ipsets del kernel de Linux (v2)

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-ipset-access
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-ipset-access

Habilita el módulo añadiendo lo siguiente al principio de /etc/nginx/nginx.conf:

load_module modules/ngx_http_ipset_access.so;

Este documento describe nginx-module-ipset-access v2.0.9 lanzado el 20 de diciembre de 2025.


Control de acceso basado en IP de nivel empresarial para NGINX usando ipset de Linux. Bloquea amenazas, limita la tasa de abusadores, desafía bots y protege tu infraestructura.

Version GetPageSpeed

⚠️ Software Comercial
Este es un módulo premium de código cerrado disponible exclusivamente a través del GetPageSpeed Repository.

✨ Características

Características Principales

Característica Descripción
Lista blanca/Lista negra Permitir o denegar según la membresía de ipset
Múltiples ipsets Comprobar contra múltiples ipsets en una directiva
Actualizaciones en vivo Modificar ipsets sin recargar NGINX
Códigos de estado personalizados Devolver cualquier estado HTTP al bloquear

Características de Rendimiento

Característica Descripción
Sesiones por hilo Sesiones libipset locales por hilo eliminan la contención de bloqueo
Cache LRU Caché de memoria compartida con TTL configurable
Tasas de aciertos de caché Típicamente 95%+ de tasa de aciertos reduce las llamadas al kernel

Características de Seguridad

Característica Descripción
Limitación de tasa Limitar solicitudes por IP con ventanas configurables
Auto-baneo Añadir automáticamente a la lista negra a los violadores de la limitación de tasa
Desafío JS Desafío de prueba de trabajo detiene bots automatizados
Trampas de honeypot Auto-bloquear IPs que acceden a URLs trampa
Tiempo de espera de entrada Expirar automáticamente las entradas de la lista negra

Características Operativas

Característica Descripción
Modo de prueba Probar configuración sin bloquear
Fallo abierto/cerrado Controlar el comportamiento en errores de ipset
Métricas de Prometheus Endpoint nativo /metrics para Grafana
Estadísticas JSON API de estadísticas detalladas
Variables de NGINX $ipset_result y $ipset_matched_set
##

🚀 Inicio Rápido

1. Crear ipsets

## Crear una lista negra
sudo ipset create bad_guys hash:ip timeout 86400

## Crear una lista de prohibición por limitación de tasa  
sudo ipset create ratelimited hash:ip timeout 1800

## Crear una lista de trampas de honeypot
sudo ipset create honeypot hash:ip timeout 86400

2. Configurar NGINX

load_module modules/ngx_http_ipset_access_module.so;

http {
    server {
        listen 80;

        # Bloquear IPs malas conocidas
        ipset_blacklist bad_guys;

        # Limitación de tasa: 100 solicitudes por minuto
        ipset_ratelimit rate=100 window=60s autoban=ratelimited;

        # Tu contenido
        location / {
            root /var/www/html;
        }

        # Trampa de honeypot - devuelve 404 por defecto
        location /wp-admin.php {
            ipset_autoadd honeypot timeout=86400;
        }

        # Endpoint de métricas
        location /metrics {
            ipset_metrics;
            allow 127.0.0.1;
            deny all;
        }
    }
}

3. Probar y recargar

sudo nginx -t && sudo nginx -s reload

📦 Instalación

Este módulo está disponible exclusivamente a través del GetPageSpeed Premium Repository.

Paso 1: Suscribirse al GetPageSpeed Repository

Visita GetPageSpeed Repository Subscription para obtener acceso.

Paso 2: Instalar el Repositorio

## RHEL/CentOS/Rocky/Alma Linux 8+
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm

Paso 3: Instalar el Módulo

sudo dnf install nginx-module-ipset-access

Paso 4: Habilitar el Módulo

Añadir a /etc/nginx/nginx.conf antes de cualquier bloque http {}:

load_module modules/ngx_http_ipset_access_module.so;

Paso 5: Recargar NGINX

sudo nginx -t && sudo systemctl reload nginx

📖 Referencia de Configuración

Control de Acceso

ipset_blacklist set1 [set2 ...]

Contexto: http, server
Predeterminado:

Bloquea solicitudes si la IP del cliente aparece en cualquiera de los ipsets listados. Se comprueban múltiples ipsets en orden hasta que se encuentra una coincidencia.

## Conjunto único
ipset_blacklist bad_guys;

## Múltiples conjuntos (lógica OR - bloqueado si está en CUALQUIER conjunto)
ipset_blacklist spammers hackers tor_exits;

## Desactivar
ipset_blacklist off;

ipset_whitelist set1 [set2 ...]

Contexto: http, server
Predeterminado:

Permite solicitudes solo si la IP del cliente aparece en al menos uno de los ipsets listados. Todas las demás IPs son rechazadas.

## Solo permitir IPs de confianza
ipset_whitelist trusted_partners office_ips;

Importante: Las IPs en la lista blanca evitan todas las restricciones del módulo, incluyendo: - Limitación de tasa (ipset_ratelimit) - Desafíos de JavaScript (ipset_challenge)

Esto es útil para IPs de administradores que no deberían estar sujetas a limitaciones de tasa o desafíos:

## Las IPs de administradores evitan la limitación de tasa y desafíos
ipset_whitelist admin_ips;
ipset_ratelimit rate=100 window=1m autoban=ratelimited ban_time=1800;
ipset_challenge on;

ipset_status code

Contexto: http, server
Predeterminado: 403

Código de estado HTTP devuelto cuando se bloquea una solicitud.

ipset_status 403;   # Prohibido (predeterminado)
ipset_status 444;   # Cerrar conexión sin respuesta (especial de NGINX)
ipset_status 429;   # Demasiadas Solicitudes
ipset_status 503;   # Servicio No Disponible

Caché y Rendimiento

ipset_cache_ttl time

Contexto: http, server
Predeterminado: 60s

Cuánto tiempo almacenar en caché los resultados de búsqueda de ipset. Los resultados en caché evitan llamadas repetidas al kernel para la misma IP.

ipset_cache_ttl 30s;    # 30 segundos
ipset_cache_ttl 5m;     # 5 minutos
ipset_cache_ttl 1h;     # 1 hora

Nota de Depuración: Si eliminas una IP de un ipset pero el módulo aún la informa como "coincidente", esto se debe a la caché. El resultado en caché expirará después del TTL configurado. Para un efecto inmediato durante las pruebas, puedes establecer temporalmente ipset_cache_ttl 0; para desactivar la caché (no recomendado para producción debido al impacto en el rendimiento).

Impacto en el Rendimiento: - TTL más alto = Mejor rendimiento, pero más lento para reflejar cambios en ipset - TTL más bajo = Más sensible a cambios en ipset, pero más llamadas al kernel - Recomendado: 30s a 5m para la mayoría de los casos de uso

ipset_fail_open on|off

Contexto: http, server
Predeterminado: off

Controla el comportamiento cuando una búsqueda de ipset falla (por ejemplo, el conjunto no existe).

ipset_fail_open off;   # Denegar en error (seguro, predeterminado)
ipset_fail_open on;    # Permitir en error (disponible pero arriesgado)

ipset_dryrun on|off

Contexto: http, server
Predeterminado: off

Cuando está habilitado, registra lo que se bloquearía pero no bloquea realmente. Perfecto para probar nuevas reglas en producción.

ipset_dryrun on;   # Registrar pero no bloquear

Verifica los registros para mensajes como:

ipset: DRYRUN would block 1.2.3.4 (matched: bad_guys)

Importante: Al usar las variables $ipset_result y $ipset_matched_set con el modo dryrun, estos valores reflejan el estado en el momento en que se procesó la solicitud, no el estado actual del ipset. Si verificas el ipset manualmente más tarde y no encuentras la IP, las razones posibles incluyen:

  1. Expiración del tiempo de espera: La IP fue añadida con un tiempo de espera (por ejemplo, timeout=86400) y ha expirado desde entonces.
  2. Retraso de caché: El módulo almacena en caché los resultados de búsqueda (predeterminado 60s). Una entrada eliminada del ipset puede seguir mostrando como "coincidente" hasta que la caché expire.
  3. Eliminación manual: Alguien o algo (fail2ban, scripts) eliminó la entrada.

Este es un comportamiento esperado: el dryrun te muestra exactamente lo que la producción vería en el momento de la solicitud.

Limitación de Tasa

ipset_ratelimit parameters

Contexto: http, server
Predeterminado:

Limita las solicitudes por IP dentro de una ventana de tiempo. Puede añadir automáticamente a los violadores a un ipset.

Parámetros:

Parámetro Requerido Descripción
rate=N Máximo de solicitudes por ventana
window=TIME No Ventana de tiempo (predeterminado: 60s)
autoban=SET No ipset para añadir a los violadores
ban_time=N No Segundos hasta auto-expirar (predeterminado: 3600)

Ejemplos:

## Básico: 100 solicitudes por minuto
ipset_ratelimit rate=100;

## Con ventana personalizada: 1000 solicitudes por hora
ipset_ratelimit rate=1000 window=1h;

## Con auto-baneo: Añadir a los violadores al ipset por 30 minutos
ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

## Protección estricta de API
ipset_ratelimit rate=10 window=1s autoban=api_abusers ban_time=3600;

Cómo funciona: 1. Cada IP recibe un contador de solicitudes y un tiempo de inicio de ventana. 2. El contador se incrementa en cada solicitud. 3. Cuando la ventana expira, el contador se reinicia. 4. Si el contador supera rate, devuelve 429 Too Many Requests. 5. Si autoban está configurado, la IP se añade al ipset especificado.

Nota: El estado de limitación de tasa se almacena en memoria compartida y sobrevive a los reinicios de trabajadores.

Desafío de JavaScript

ipset_challenge on|off

Contexto: http, server
Predeterminado: off

Habilita el modo de desafío de JavaScript. Los navegadores deben resolver un rompecabezas de prueba de trabajo para acceder al sitio. Efectivo contra bots automatizados y raspadores.

ipset_challenge on;

Cómo funciona: 1. La primera solicitud recibe una página de desafío (HTTP 503). 2. El navegador ejecuta JavaScript que resuelve un rompecabezas de hash. 3. La solución se almacena en una cookie (_ipset_verified). 4. Solicitudes posteriores con una cookie válida pasan. 5. La cookie expira después de 24 horas.

ipset_challenge_difficulty level

Contexto: http, server
Predeterminado: 2

Controla la dificultad del desafío (1-8). Mayor = más tiempo para resolver.

Nivel Tiempo Aproximado de Resolución
1 ~100ms
2 ~500ms (predeterminado)
3 ~1 segundo
4 ~2 segundos
5 ~5 segundos
6+ ~10+ segundos
ipset_challenge on;
ipset_challenge_difficulty 3;  # ~1 segundo de tiempo de resolución

Características de la Página de Desafío: - Diseño moderno y responsivo - Spinner de carga animado - Retroalimentación de progreso - Redirección automática en caso de éxito - Sin dependencias externas

Auto-adición de Honeypot

ipset_autoadd setname [timeout=seconds] [status=code]

Contexto: server, location
Predeterminado:

Añade automáticamente la IP del cliente al ipset especificado cuando se accede a la ubicación y devuelve un código de estado HTTP. Perfecto para trampas de honeypot.

Parámetros:

Parámetro Requerido Descripción
setname Nombre del ipset objetivo
timeout=N No Tiempo de espera de la entrada en segundos
status=N No Código de estado HTTP a devolver (predeterminado: 404)

Ejemplos:

## Básico: Añadir al conjunto de honeypot y devolver 404 (predeterminado)
location /config.php {
    ipset_autoadd honeypot;
}

## Con tiempo de espera: Auto-expirar después de 24 horas
location /wp-admin.php {
    ipset_autoadd scanners timeout=86400;
}

## Devolver 403 Prohibido en lugar de 404
location /admin.php {
    ipset_autoadd honeypot timeout=86400 status=403;
}

## Devolver 429 Demasiadas Solicitudes
location /api/hack {
    ipset_autoadd abusers timeout=3600 status=429;
}

Rutas Comunes de Honeypot:

## Trampas de WordPress - devolver 404 para parecer un archivo faltante
location ~ ^/(wp-admin\.php|wp-login\.php|xmlrpc\.php)$ {
    ipset_autoadd honeypot timeout=86400;
}

## Trampas de archivos de configuración - devolver 403 para simular acceso prohibido
location ~ ^/(\\.env|config\\.php|phpinfo\\.php)$ {
    ipset_autoadd honeypot timeout=86400 status=403;
}

## Trampas de shell/exploit - severo, bloquear por 1 semana
location ~ ^/(shell|cmd|eval|exec)\\.php$ {
    ipset_autoadd malicious timeout=604800 status=403;
}

Nota: Cuando una IP es auto añadida, el módulo devuelve inmediatamente el código de estado HTTP especificado (predeterminado 404), evitando el procesamiento adicional de solicitudes. El keep-alive de la conexión también se desactiva para evitar más solicitudes en la misma conexión.

Observabilidad

ipset_stats

Contexto: location
Predeterminado:

Habilita el endpoint de estadísticas JSON.

location = /_stats {
    ipset_stats;
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    deny all;
}

Consulta JSON Stats API para el formato de respuesta.

ipset_metrics

Contexto: location
Predeterminado:

Habilita el endpoint de métricas de Prometheus.

location = /metrics {
    ipset_metrics;
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    deny all;
}

Consulta Prometheus Metrics para las métricas disponibles.

📝 Variables de NGINX

El módulo expone dos variables para usar en registros, encabezados o condicionales.

$ipset_result

La decisión de acceso tomada para esta solicitud.

Valor Descripción
allow Solicitud permitida
deny Solicitud bloqueada
dryrun Sería bloqueada (modo de prueba)
ratelimited Límite de tasa excedido
challenged Página de desafío servida

$ipset_matched_set

Nombre del ipset que coincidió (si lo hay). Vacío si no hay coincidencia.

Nota: Esta variable refleja el estado de coincidencia en el momento de la solicitud, no el estado actual del ipset. Si verificas el ipset manualmente y no encuentras la IP: - La entrada puede haber expirado (los ipsets soportan tiempos de espera por entrada) - La caché del módulo (predeterminado 60s) puede mostrar una entrada recientemente eliminada como aún coincidente - Algo puede haber eliminado la entrada después de que se procesó la solicitud

Ejemplos de Uso

Registro de acceso personalizado:

log_format security '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    'ipset_result="$ipset_result" '
                    'matched_set="$ipset_matched_set"';

access_log /var/log/nginx/security.log security;

Agregar encabezados para depuración:

add_header X-IPSet-Result $ipset_result always;
add_header X-IPSet-Matched $ipset_matched_set always;

Registro condicional:

## Solo registrar solicitudes bloqueadas
map $ipset_result $loggable {
    "deny"  1;
    default 0;
}

access_log /var/log/nginx/blocked.log combined if=$loggable;

📊 Métricas de Prometheus

El endpoint /metrics devuelve métricas en formato de exposición de Prometheus.

Métricas Disponibles

## HELP nginx_ipset_requests_total Total de solicitudes procesadas
## TYPE nginx_ipset_requests_total counter
nginx_ipset_requests_total{result="checked"} 1234567
nginx_ipset_requests_total{result="allowed"} 1234000
nginx_ipset_requests_total{result="blocked"} 500
nginx_ipset_requests_total{result="error"} 67

## HELP nginx_ipset_cache_total Operaciones de caché
## TYPE nginx_ipset_cache_total counter
nginx_ipset_cache_total{result="hit"} 1200000
nginx_ipset_cache_total{result="miss"} 34567

## HELP nginx_ipset_cache_entries Entradas de caché actuales
## TYPE nginx_ipset_cache_entries gauge
nginx_ipset_cache_entries 5432

## HELP nginx_ipset_autoadd_total Operaciones de auto-adición
## TYPE nginx_ipset_autoadd_total counter
nginx_ipset_autoadd_total{result="success"} 42
nginx_ipset_autoadd_total{result="failed"} 3

## HELP nginx_ipset_ratelimit_total Eventos de limitación de tasa
## TYPE nginx_ipset_ratelimit_total counter
nginx_ipset_ratelimit_total{action="triggered"} 156
nginx_ipset_ratelimit_total{action="autobanned"} 23

## HELP nginx_ipset_challenge_total Eventos de desafío
## TYPE nginx_ipset_challenge_total counter
nginx_ipset_challenge_total{result="issued"} 1000
nginx_ipset_challenge_total{result="passed"} 950
nginx_ipset_challenge_total{result="failed"} 50

## HELP nginx_ipset_uptime_seconds Tiempo de actividad del módulo
## TYPE nginx_ipset_uptime_seconds gauge
nginx_ipset_uptime_seconds 86400

Consultas de Dashboard de Grafana

Tasa de solicitudes por resultado:

rate(nginx_ipset_requests_total[5m])

Tasa de bloqueos:

rate(nginx_ipset_requests_total{result="blocked"}[5m])

Tasa de aciertos de caché:

rate(nginx_ipset_cache_total{result="hit"}[5m]) / 
(rate(nginx_ipset_cache_total{result="hit"}[5m]) + rate(nginx_ipset_cache_total{result="miss"}[5m]))

Disparadores de limitación de tasa por minuto:

rate(nginx_ipset_ratelimit_total{action="triggered"}[1m]) * 60

📈 JSON Stats API

El endpoint /_stats devuelve estadísticas detalladas en formato JSON.

Formato de Respuesta

{
  "version": "2.0.7",
  "uptime_seconds": 86400,
  "requests": {
    "checked": 1234567,
    "allowed": 1234000,
    "blocked": 500,
    "errors": 67
  },
  "cache": {
    "hits": 1200000,
    "misses": 34567,
    "entries": 5432,
    "hit_rate": 97.20
  },
  "autoadd": {
    "success": 42,
    "failed": 3
  },
  "ratelimit": {
    "triggered": 156,
    "autobanned": 23
  },
  "challenge": {
    "issued": 1000,
    "passed": 950,
    "failed": 50
  }
}

Descripciones de Campos

Campo Descripción
version Versión del módulo
uptime_seconds Segundos desde que se cargó el módulo
requests.checked Total de solicitudes procesadas
requests.allowed Solicitudes que pasaron
requests.blocked Solicitudes que fueron bloqueadas
requests.errors Errores de búsqueda de ipset
cache.hits Aciertos de caché (evitó llamada al kernel)
cache.misses Fallos de caché (requirió llamada al kernel)
cache.entries Entradas en caché actuales
cache.hit_rate Porcentaje de tasa de aciertos
autoadd.success Adiciones de honeypot exitosas
autoadd.failed Adiciones de honeypot fallidas
ratelimit.triggered Violaciones de limitación de tasa
ratelimit.autobanned IPs auto añadidas a la lista de prohibición
challenge.issued Páginas de desafío servidas
challenge.passed Desafíos resueltos exitosamente
challenge.failed Fallos en el desafío
##

🏗️ Arquitectura

┌─────────────────────────────────────────────────────────────────────┐
│                           FLUJO DE SOLICITUD                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Solicitud Entrante                                                │
│         │                                                            │
│         ▼                                                            │
│   ┌───────────────┐                                                  │
│   │  Comprobación  │──── ¿Excedido? ────▶ 429 + Auto-baneo          │
│   │   de Tasa     │                                                  │
│   └───────┬───────┘                                                  │
│           │ OK                                                       │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Comprobación │──── ¿Sin cookie? ────▶ Servir rompecabezas JS │
│   │    de Desafío  │                                                  │
│   └───────┬───────┘                                                  │
│           │ Pasado                                                   │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  Comprobación  │────▶│   ACIERTO   │────▶ Usar resultado en caché│
│   │     de Caché   │     └─────────────┘                             │
│   └───────┬───────┘                                             │
│           │ FALLO                                                     │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  Consulta de   │──── Sesión libipset local por hilo              │
│   │   ipset       │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ Almacenar en   │                                                  │
│   │     Caché      │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    Decisión    │──── ¿Coincidencia en lista negra? ────▶ Bloquear (403/444) │
│   │                │──── ¿Fallo en lista blanca? ────▶ Bloquear (403/444) │
│   └───────┬───────┘                                                  │
│           │ Permitir                                                  │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Comprobación │──── ¿Coincidencia en ubicación? ────▶ Añadir a ipset│
│   │     de Honeypot│                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│       Continuar a                                                  │
│       Manejador de Contenido                                        │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                        MEMORIA COMPARTIDA                           │
│  ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│  │     Estadísticas│    Caché LRU    │    Cubos de Limitación de Tasa │ │
│  │   (contadores)  │  (IP → Resultado)│   (IP → Contador de Solicitudes) │ │
│  └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

Disposición de la Memoria

Componente Ubicación Propósito
Sesión libipset Local por hilo Sesión por trabajador para evitar bloqueos
Caché de búsqueda Memoria compartida Caché LRU de asignaciones IP→resultado
Cubos de limitación de tasa Memoria compartida Contadores de solicitudes por IP
Estadísticas Memoria compartida Contadores atómicos para métricas
##

📚 Ejemplos

Ejemplo 1: Lista Negra Básica

## Crear ipset
sudo ipset create blacklist hash:ip
sudo ipset add blacklist 1.2.3.4
    server {
    listen 80;

    ipset_blacklist blacklist;

    location / {
        root /var/www/html;
    }
}

Ejemplo 2: API con Limitación de Tasa

server {
    listen 80;

    # Limitación de tasa estricta para API
    ipset_ratelimit rate=100 window=1m autoban=api_banned ban_time=3600;

    # Solo permitir socios conocidos
    ipset_whitelist api_partners;
    ipset_status 401;

    location /api/ {
        proxy_pass http://backend;
    }
}

Ejemplo 3: Stack de Seguridad Completo

    server {
        listen 80 default_server;

    # Capa 1: Amenazas conocidas
    ipset_blacklist malware_ips tor_exits datacenter_ranges;
    ipset_status 444;
    ipset_cache_ttl 5m;

    # Capa 2: Limitación de tasa
    ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

    # Capa 3: Desafío de bots
    ipset_challenge on;
    ipset_challenge_difficulty 2;

    # Contenido real
        location / {
        root /var/www/html;
    }

    # Trampas de honeypot - devolver 404 (predeterminado) para parecer archivos faltantes
    location ~ ^/(wp-admin|phpmyadmin|admin)\.php$ {
        ipset_autoadd honeypot timeout=86400;
    }

    # Monitoreo
    location = /metrics {
        ipset_metrics;
        allow 10.0.0.0/8;
        deny all;
    }
}

Ejemplo 4: Pruebas en Modo de Prueba

server {
    listen 80;

    # Probar nuevas reglas sin bloquear
    ipset_blacklist new_threat_list;
    ipset_dryrun on;

    location / {
        root /var/www/html;
    }
}

Verifica los registros:

tail -f /var/log/nginx/error.log | grep "DRYRUN"

🔧 Solución de Problemas

Módulo no cargando

nginx: [emerg] dlopen() failed

Solución: Asegúrate de que NGINX fue construido con --with-compat y que el módulo fue construido contra la misma versión de NGINX.

ipset no encontrado

ipset: INVALID_SETNAME

Solución: Crea el ipset antes de iniciar NGINX:

sudo ipset create myset hash:ip

Permiso denegado

ipset: kernel error

Solución: El trabajador de NGINX necesita la capacidad CAP_NET_ADMIN:

sudo setcap cap_net_admin+ep /usr/sbin/nginx

Negaciones de SELinux (RHEL/CentOS/AlmaLinux)

SELinux está impidiendo que /usr/sbin/nginx acceda a getattr en el netlink_netfilter_socket

Solución: Instala el módulo de política de SELinux incluido:

cd selinux/
sudo ./install.sh

O manualmente:

## Verificar
semodule -l | grep nginx_ipset

La política permite que httpd_t (el dominio SELinux de NGINX) use sockets netlink_netfilter requeridos por libipset.

Alto uso de memoria

Solución: Reduce el TTL de caché o limita el tamaño de la caché en la configuración de memoria compartida.

La limitación de tasa no funciona

Solución: Asegúrate de que el ipset para auto-baneo exista y tenga soporte para tiempos de espera:

sudo ipset create ratelimited hash:ip timeout 3600

El registro muestra "matched=setname" pero la IP no está en el ipset

Este es un comportamiento esperado. El módulo informa lo que vio en el momento de la solicitud. Si verificas el ipset más tarde y no encuentras la IP:

  1. Expiración del tiempo de espera: La IP fue añadida con un tiempo de espera y ha expirado desde entonces.

    # Verifica si el conjunto soporta tiempos de espera
    ipset list setname | head -5
    # Busca "timeout" en el encabezado
    

  2. Caché del módulo: El módulo almacena en caché las búsquedas (predeterminado 60s). Una IP recientemente eliminada puede seguir apareciendo como "coincidente".

    # Desactivar temporalmente la caché para depuración (¡no para producción!)
    ipset_cache_ttl 0;
    

  3. La entrada fue eliminada: fail2ban, scripts o comandos manuales pueden haberla eliminado.

  4. Problema de configuración de trampa: Si usas trampas de honeypot con ipset_autoadd, bots legítimos pueden haber activado trampas. Verifica que tus ubicaciones de trampa no se superpongan con rutas legítimas de bots (como sitemaps, robots.txt). Usa robots.txt para excluir rutas de trampa de rastreo.

autoadd falla con "result=4"

Esto significa que estás usando timeout=N en ipset_autoadd pero el ipset fue creado sin soporte para tiempos de espera.

Solución: Recréalo con soporte para tiempos de espera:

## Usando ipset directamente
sudo ipset destroy honeypot4
sudo ipset create honeypot4 hash:ip family inet timeout 86400

## Usando firewall-cmd (RHEL/CentOS/Amazon Linux)
sudo firewall-cmd --permanent --delete-ipset=honeypot4
sudo firewall-cmd --permanent --new-ipset=honeypot4 --type=hash:ip \
    --option=family=inet --option=timeout=86400
sudo firewall-cmd --reload

📋 Requisitos

  • NGINX ≥ 1.22 (construido con --with-compat)
  • Kernel de Linux con soporte para ipset (módulo nf_tables o xt_set)
  • Biblioteca libipset y encabezados de desarrollo
  • Capacidades: CAP_NET_ADMIN para operaciones de ipset

📜 Licencia

Este es un software propietario. Todos los derechos reservados.

Disponible exclusivamente a través del GetPageSpeed Premium Repository.

👤 Autor

Danila Vershinin
GetPageSpeed LLC

🆘 Soporte

Módulo de Acceso IPSet de NGINX
Un módulo premium de NGINX por GetPageSpeed LLC
www.getpagespeed.com