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 GetPageSpeed NGINX Extras.
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 en la parte superior de /etc/nginx/nginx.conf:
load_module modules/ngx_http_ipset_access_module.so;
Este documento describe nginx-module-ipset-access v2.0.10 lanzado el 13 de junio de 2026.
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.
⚠️ Software Comercial
Este es un módulo premium de código cerrado disponible exclusivamente a través del GetPageSpeed Repository.Requisito de plan: Requiere el plan Pro de la suscripción de GetPageSpeed NGINX Extras.
✨ 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 más del 95% de tasa de aciertos reduce 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 | El desafío de prueba de trabajo detiene bots automatizados |
| Trampas de honeypot | Auto-bloquear IPs que acceden a URLs trampa |
| Tiempo de entrada | Expirar automáticamente entradas de la lista negra |
Características Operativas
| Característica | Descripción |
|---|---|
| Modo de prueba | Probar la 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 baneo 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
Por defecto: —
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;
# Deshabilitar
ipset_blacklist off;
ipset_whitelist set1 [set2 ...]
Contexto: http, server
Por defecto: —
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
Por defecto: 403
Código de estado HTTP devuelto cuando se bloquea una solicitud.
ipset_status 403; # Prohibido (por defecto)
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
Por defecto: 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 reporta 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 deshabilitar 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
Por defecto: off
Controla el comportamiento cuando falla una búsqueda de ipset (por ejemplo, el conjunto no existe).
ipset_fail_open off; # Denegar en error (seguro, por defecto)
ipset_fail_open on; # Permitir en error (disponible pero arriesgado)
ipset_dryrun on|off
Contexto: http, server
Por defecto: 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
Revisa 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 en modo de prueba, estos valores reflejan el estado en el momento en que se procesó la solicitud, no el estado actual del ipset. Si revisas el ipset manualmente más tarde y no encuentras la IP, las razones posibles incluyen:
- 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. - Retraso de caché: El módulo almacena en caché los resultados de búsqueda (por defecto 60s). Una entrada eliminada del ipset puede seguir apareciendo como "coincidente" hasta que la caché expire.
- Eliminación manual: Alguien o algo (fail2ban, scripts) eliminó la entrada.
Este es un comportamiento esperado: el modo de prueba 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
Por defecto: —
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 |
Sí | Máximo de solicitudes por ventana |
window=TIME |
No | Ventana de tiempo (por defecto: 60s) |
autoban=SET |
No | ipset para añadir violadores |
ban_time=N |
No | Segundos hasta la expiración automática (por defecto: 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 violadores a 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 obtiene 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 restablece.
4. Si el contador excede rate, devuelve 429 Too Many Requests.
5. Si se establece autoban, la IP se añade al ipset especificado.
Nota: El estado de la 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
Por defecto: 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 hash.
3. La solución se almacena en una cookie (_ipset_verified).
4. Las solicitudes subsiguientes con una cookie válida pasan.
5. La cookie expira después de 24 horas.
ipset_challenge_difficulty level
Contexto: http, server
Por defecto: 2
Controla la dificultad del desafío (1-8). Mayor = mayor tiempo de resolución.
| Nivel | Tiempo Aproximado de Resolución |
|---|---|
| 1 | ~100ms |
| 2 | ~500ms (por defecto) |
| 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
Por defecto: —
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 | Sí | 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 (por defecto: 404) |
Ejemplos:
# Básico: Añadir al conjunto de honeypot y devolver 404 (por defecto)
location /config.php {
ipset_autoadd honeypot;
}
# Con tiempo de espera: Expirar automáticamente 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 - severas, bloquear por 1 semana
location ~ ^/(shell|cmd|eval|exec)\\.php$ {
ipset_autoadd malicious timeout=604800 status=403;
}
Nota: Cuando una IP es auto-agregada, el módulo devuelve inmediatamente el código de estado HTTP especificado (por defecto 404), evitando el procesamiento adicional de la solicitud. 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
Por defecto: —
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
Por defecto: —
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 su uso 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 revisas 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 (por defecto 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 del 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
📈 API de Estadísticas JSON
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 de 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-agregadas a la lista de baneos |
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 │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Verificación │──── ¿Excedido? ────▶ 429 + Auto-baneo │
│ │ de Tasa │ │
│ └───────┬───────┘ │
│ │ OK │
│ ▼ │
│ ┌───────────────┐ │
│ │ Verificación │──── ¿Sin cookie? ────▶ Servir Rompecabezas JS │
│ │ de Desafío │ │
│ └───────┬───────┘ │
│ │ Pasado │
│ ▼ │
│ ┌───────────────┐ ┌─────────────┐ │
│ │ Verificación │────▶│ ACIERTO │────▶ Usar resultado en caché│
│ └───────┬───────┘ └─────────────┘ │
│ │ FALLA │
│ ▼ │
│ ┌───────────────┐ │
│ │ Consulta de │──── Sesión libipset local por hilo │
│ │ ipset │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Almacenar en │ │
│ │ Caché │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Decisión │──── ¿Coincidencia en lista negra? ────▶ Bloquear (403/444) │
│ │ │──── ¿Falta en lista blanca? ────▶ Bloquear (403/444) │
│ └───────┬───────┘ │
│ │ Permitir │
│ ▼ │
│ ┌───────────────┐ │
│ │ Verificación │──── ¿Coincidencia en ubicación? ────▶ Añadir a ipset │
│ │ de Honeypot │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ Continuar hacia │
│ Manejador de Contenido │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ MEMORIA COMPARTIDA │
│ ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│ │ Estadísticas│ Caché LRU │ Cubos de Limitación de Tasa│ │
│ │ (contadores) │ (IP → Resultado)│ (IP → Contador de Solicitudes)│ │
│ └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Diseño de 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 mapeos 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 para bots
ipset_challenge on;
ipset_challenge_difficulty 2;
# Contenido real
location / {
root /var/www/html;
}
# Trampas de honeypot - devolver 404 (por defecto) 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;
}
}
Revisa 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.
firewalld + nftables backend + fuentes ipset: (Rocky/RHEL 9)
Si estás usando firewalld con el backend predeterminado nftables y tratas de adjuntar ipsets gestionados por el módulo a zonas con:
firewall-cmd --permanent --zone=drop --add-source=ipset:honeypot4
firewall-cmd --reload
puede fallar en la recarga con errores como:
COMMAND_FAILED: 'python-nftables' failed: ... Error: No such file or directory
Razón (corta): El backend nftables de firewalld usa nft sets para fuentes ipset:, mientras que este módulo usa kernel ipsets a través de libipset. Estos son subsistemas diferentes, por lo que no interoperan.
Recomendación: Si deseas hacer cumplir el firewall "antes de NGINX" impulsado por los auto-baneos de este módulo, configura firewalld para usar el backend iptables:
sudo sed -i 's/^FirewallBackend=.*/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
sudo systemctl restart firewalld
sudo firewall-cmd --reload
Idea futura: Un módulo separado que hable con conjuntos de nftables (por ejemplo, “nfset-access”) podría soportar el backend nft de firewalld de manera nativa, pero eso requeriría bibliotecas/API de nftables y está fuera del alcance de este módulo solo de libipset.
Alto uso de memoria
Solución: Reduce el TTL de la 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 de tiempo 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 reporta lo que vio en el momento de la solicitud. Si revisas el ipset más tarde y no encuentras la IP:
-
Expiración del tiempo de espera: La IP fue añadida con un tiempo de espera y ha expirado desde entonces.
# Verificar si el conjunto soporta tiempos de espera ipset list setname | head -5 # Busca "timeout" en el encabezado -
Caché del módulo: El módulo almacena en caché las búsquedas (por defecto 60s). Una IP recientemente eliminada puede seguir apareciendo como "coincidente".
# Deshabilitar temporalmente la caché para depuración (¡no para producción!) ipset_cache_ttl 0; -
La entrada fue eliminada: fail2ban, scripts o comandos manuales pueden haberla eliminado.
-
Problema de configuración de trampa: Si usas trampas de honeypot con
ipset_autoadd, bots legítimos pueden haber activado trampas. Revisa que tus ubicaciones de trampa no se superpongan con rutas legítimas de bots (como sitemaps, robots.txt). Usarobots.txtpara excluir rutas de trampa del rastreo.
autoadd falla con "result=4"
Esto significa que estás usando timeout=N en ipset_autoadd pero el ipset fue creado sin soporte de tiempo de espera.
Solución: Recrea el ipset con soporte de tiempo 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 de ipset (
ip_set+ soporte de netfilter/x_tables; comúnmente disponible en RHEL/Rocky/Alma/Amazon Linux) - Biblioteca y encabezados de desarrollo de libipset
- Capacidades:
CAP_NET_ADMINpara 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
- Honeypot v2.0 Usando ipset-access para auto-baneo de bots
- Soporte: Disponible para suscriptores premium
- Contacto: GetPageSpeed Support
Módulo de Acceso IPSet de NGINX
Un módulo premium de NGINX por GetPageSpeed LLC
www.getpagespeed.com