Pular para conteúdo

ipset-access: Bloqueio de IP com zero latência usando ipsets do kernel Linux (v2)

Requer o plano Pro (ou superior) da assinatura GetPageSpeed NGINX Extras.

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e 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

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_ipset_access.so;

Este documento descreve nginx-module-ipset-access v2.0.9 lançado em 20 de dezembro de 2025.


Controle de acesso baseado em IP de nível empresarial para NGINX usando ipset do Linux. Bloqueie ameaças, limite a taxa de abusadores, desafie bots e proteja sua infraestrutura.

Version GetPageSpeed

⚠️ Software Comercial
Este é um módulo premium de código fechado disponível exclusivamente através do GetPageSpeed Repository.

✨ Recursos

Recursos Principais

Recurso Descrição
Lista Branca/Lista Negra Permitir ou negar com base na associação ao ipset
Múltiplos ipsets Verificar contra múltiplos ipsets em uma diretiva
Atualizações ao vivo Modificar ipsets sem recarregar o NGINX
Códigos de status personalizados Retornar qualquer status HTTP ao bloquear

Recursos de Desempenho

Recurso Descrição
Sessões por thread Sessões libipset locais por thread eliminam contenção de bloqueio
Cache LRU Cache de memória compartilhada com TTL configurável
Taxas de acerto de cache Taxa de acerto tipicamente superior a 95% reduz chamadas ao kernel

Recursos de Segurança

Recurso Descrição
Limitação de taxa Limitar solicitações por IP com janelas configuráveis
Auto-banimento Adicionar automaticamente à lista negra violadores de limite de taxa
Desafio JS Desafio de prova de trabalho impede bots automatizados
Armadilhas Honeypot Auto-bloquear IPs que acessam URLs de armadilha
Tempo limite de entrada Expiração automática de entradas na lista negra

Recursos Operacionais

Recurso Descrição
Modo de teste Testar configuração sem bloquear
Falha aberta/fechada Controlar comportamento em erros de ipset
Métricas Prometheus Endpoint nativo /metrics para Grafana
Estatísticas JSON API de estatísticas detalhadas
Variáveis NGINX $ipset_result e $ipset_matched_set
##

🚀 Início Rápido

1. Criar ipsets

## Criar uma lista negra
sudo ipset create bad_guys hash:ip timeout 86400

## Criar uma lista de banimento por limite de taxa  
sudo ipset create ratelimited hash:ip timeout 1800

## Criar uma lista de armadilha honeypot
sudo ipset create honeypot hash:ip timeout 86400

2. Configurar o NGINX

load_module modules/ngx_http_ipset_access_module.so;

http {
    server {
        listen 80;

        # Bloquear IPs ruins conhecidos
        ipset_blacklist bad_guys;

        # Limitar taxa: 100 solicitações por minuto
        ipset_ratelimit rate=100 window=60s autoban=ratelimited;

        # Seu conteúdo
        location / {
            root /var/www/html;
        }

        # Armadilha honeypot - retorna 404 por padrão
        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. Testar e recarregar

sudo nginx -t && sudo nginx -s reload

📦 Instalação

Este módulo está disponível exclusivamente através do GetPageSpeed Premium Repository.

Passo 1: Inscrever-se no GetPageSpeed Repository

Visite GetPageSpeed Repository Subscription para obter acesso.

Passo 2: Instalar o Repositório

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

Passo 3: Instalar o Módulo

sudo dnf install nginx-module-ipset-access

Passo 4: Ativar o Módulo

Adicione a /etc/nginx/nginx.conf antes de qualquer bloco http {}:

load_module modules/ngx_http_ipset_access_module.so;

Passo 5: Recarregar o NGINX

sudo nginx -t && sudo systemctl reload nginx

📖 Referência de Configuração

Controle de Acesso

ipset_blacklist set1 [set2 ...]

Contexto: http, server
Padrão:

Bloqueia solicitações se o IP do cliente aparecer em qualquer um dos ipsets listados. Múltiplos ipsets são verificados em ordem até que uma correspondência seja encontrada.

## Conjunto único
ipset_blacklist bad_guys;

## Múltiplos conjuntos (lógica OR - bloqueado se em QUALQUER conjunto)
ipset_blacklist spammers hackers tor_exits;

## Desativar
ipset_blacklist off;

ipset_whitelist set1 [set2 ...]

Contexto: http, server
Padrão:

Permite solicitações somente se o IP do cliente aparecer em pelo menos um dos ipsets listados. Todos os outros IPs são rejeitados.

## Permitir apenas IPs confiáveis
ipset_whitelist trusted_partners office_ips;

Importante: IPs na lista branca ignoram todas as restrições do módulo, incluindo: - Limitação de taxa (ipset_ratelimit) - Desafios em JavaScript (ipset_challenge)

Isso é útil para IPs de administradores que não devem estar sujeitos a limites de taxa ou desafios:

## IPs de administradores ignoram limites de taxa e desafios
ipset_whitelist admin_ips;
ipset_ratelimit rate=100 window=1m autoban=ratelimited ban_time=1800;
ipset_challenge on;

ipset_status código

Contexto: http, server
Padrão: 403

Código de status HTTP retornado quando uma solicitação é bloqueada.

ipset_status 403;   # Proibido (padrão)
ipset_status 444;   # Fechar conexão sem resposta (especial do NGINX)
ipset_status 429;   # Muitas Solicitações
ipset_status 503;   # Serviço Indisponível

Cache & Desempenho

ipset_cache_ttl tempo

Contexto: http, server
Padrão: 60s

Quanto tempo armazenar os resultados da pesquisa de ipset. Resultados em cache evitam chamadas repetidas ao kernel para o mesmo IP.

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

Nota de Depuração: Se você remover um IP de um ipset, mas o módulo ainda o reportar como "correspondido", isso se deve ao cache. O resultado em cache expirará após o TTL configurado. Para efeito imediato durante os testes, você pode definir temporariamente ipset_cache_ttl 0; para desativar o cache (não recomendado para produção devido ao impacto no desempenho).

Impacto no Desempenho: - TTL mais alto = Melhor desempenho, mas mais lento para refletir mudanças no ipset - TTL mais baixo = Mais responsivo a mudanças no ipset, mas mais chamadas ao kernel - Recomendado: 30s a 5m para a maioria dos casos de uso

ipset_fail_open on|off

Contexto: http, server
Padrão: off

Controla o comportamento quando uma pesquisa de ipset falha (por exemplo, conjunto não existe).

ipset_fail_open off;   # Negar em erro (seguro, padrão)
ipset_fail_open on;    # Permitir em erro (disponível, mas arriscado)

ipset_dryrun on|off

Contexto: http, server
Padrão: off

Quando ativado, registra o que seria bloqueado, mas não bloqueia realmente. Perfeito para testar novas regras em produção.

ipset_dryrun on;   # Registrar, mas não bloquear

Verifique os logs para mensagens como:

ipset: DRYRUN would block 1.2.3.4 (matched: bad_guys)

Importante: Ao usar as variáveis $ipset_result e $ipset_matched_set com o modo dryrun, esses valores refletem o estado no momento em que a solicitação foi processada—não o estado atual do ipset. Se você verificar o ipset manualmente depois e não encontrar o IP, possíveis razões incluem:

  1. Expiração do tempo limite: O IP foi adicionado com um tempo limite (por exemplo, timeout=86400) e já expirou
  2. Atraso no cache: O módulo armazena em cache os resultados de pesquisa (padrão 60s). Uma entrada removida do ipset pode ainda aparecer como "correspondida" até que o cache expire
  3. Remoção manual: Alguém ou algo (fail2ban, scripts) removeu a entrada

Esse é um comportamento esperado—dryrun mostra exatamente o que a produção veria no momento da solicitação.

Limitação de Taxa

ipset_ratelimit parâmetros

Contexto: http, server
Padrão:

Limita solicitações por IP dentro de uma janela de tempo. Pode adicionar automaticamente violadores a um ipset.

Parâmetros:

Parâmetro Necessário Descrição
rate=N Sim Máximo de solicitações por janela
window=TIME Não Janela de tempo (padrão: 60s)
autoban=SET Não ipset para adicionar violadores
ban_time=N Não Segundos até expiração automática (padrão: 3600)

Exemplos:

## Básico: 100 solicitações por minuto
ipset_ratelimit rate=100;

## Com janela personalizada: 1000 solicitações por hora
ipset_ratelimit rate=1000 window=1h;

## Com auto-banimento: Adicionar violadores ao ipset por 30 minutos
ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

## Proteção estrita da API
ipset_ratelimit rate=10 window=1s autoban=api_abusers ban_time=3600;

Como funciona: 1. Cada IP recebe um contador de solicitações e um tempo de início da janela 2. O contador é incrementado a cada solicitação 3. Quando a janela expira, o contador é redefinido 4. Se o contador exceder rate, retorna 429 Too Many Requests 5. Se autoban estiver definido, o IP é adicionado ao ipset especificado

Nota: O estado da limitação de taxa é armazenado em memória compartilhada e sobrevive a reinicializações de worker.

Desafio em JavaScript

ipset_challenge on|off

Contexto: http, server
Padrão: off

Ativa o modo de desafio em JavaScript. Os navegadores devem resolver um quebra-cabeça de prova de trabalho para acessar o site. Eficaz contra bots automatizados e scrapers.

ipset_challenge on;

Como funciona: 1. A primeira solicitação recebe uma página de desafio (HTTP 503) 2. O navegador executa JavaScript que resolve um quebra-cabeça de hash 3. A solução é armazenada em um cookie (_ipset_verified) 4. Solicitações subsequentes com cookie válido passam 5. O cookie expira após 24 horas

ipset_challenge_difficulty nível

Contexto: http, server
Padrão: 2

Controla a dificuldade do desafio (1-8). Mais alto = mais tempo para resolver.

Nível Tempo Aproximado de Resolução
1 ~100ms
2 ~500ms (padrão)
3 ~1 segundo
4 ~2 segundos
5 ~5 segundos
6+ ~10+ segundos
ipset_challenge on;
ipset_challenge_difficulty 3;  # ~1 segundo de tempo de resolução

Recursos da Página de Desafio: - Design moderno e responsivo - Animação de carregamento - Feedback de progresso - Redirecionamento automático em caso de sucesso - Sem dependências externas

Auto-adicionar Honeypot

ipset_autoadd setname [timeout=segundos] [status=código]

Contexto: server, location
Padrão:

Adiciona automaticamente o IP do cliente ao ipset especificado quando a localização é acessada e retorna um código de status HTTP. Perfeito para armadilhas honeypot.

Parâmetros:

Parâmetro Necessário Descrição
setname Sim Nome do ipset alvo
timeout=N Não Tempo limite da entrada em segundos
status=N Não Código de status HTTP a retornar (padrão: 404)

Exemplos:

## Básico: Adicionar ao conjunto honeypot e retornar 404 (padrão)
location /config.php {
    ipset_autoadd honeypot;
}

## Com tempo limite: Expira automaticamente após 24 horas
location /wp-admin.php {
    ipset_autoadd scanners timeout=86400;
}

## Retornar 403 Proibido em vez de 404
location /admin.php {
    ipset_autoadd honeypot timeout=86400 status=403;
}

## Retornar 429 Muitas Solicitações
location /api/hack {
    ipset_autoadd abusers timeout=3600 status=429;
}

Caminhos Comuns de Honeypot:

## Armadilhas do WordPress - retornar 404 para parecer um arquivo ausente
location ~ ^/(wp-admin\.php|wp-login\.php|xmlrpc\.php)$ {
    ipset_autoadd honeypot timeout=86400;
}

## Armadilhas de arquivos de configuração - retornar 403 para simular acesso proibido
location ~ ^/(\\.env|config\\.php|phpinfo\\.php)$ {
    ipset_autoadd honeypot timeout=86400 status=403;
}

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

Nota: Quando um IP é auto-adicionado, o módulo retorna imediatamente o código de status HTTP especificado (padrão 404), impedindo o processamento de solicitações adicionais. O keep-alive da conexão também é desativado para evitar novas solicitações na mesma conexão.

Observabilidade

ipset_stats

Contexto: location
Padrão:

Habilita o endpoint de estatísticas JSON.

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

Veja JSON Stats API para o formato de resposta.

ipset_metrics

Contexto: location
Padrão:

Habilita o endpoint de métricas Prometheus.

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

Veja Prometheus Metrics para as métricas disponíveis.

📝 Variáveis NGINX

O módulo expõe duas variáveis para uso em logs, cabeçalhos ou condicionais.

$ipset_result

A decisão de acesso feita para esta solicitação.

Valor Descrição
allow Solicitação permitida
deny Solicitação bloqueada
dryrun Seria bloqueado (modo de teste)
ratelimited Limite de taxa excedido
challenged Página de desafio servida

$ipset_matched_set

Nome do ipset que correspondeu (se houver). Vazio se não houver correspondência.

Nota: Esta variável reflete o estado de correspondência no momento da solicitação, não o estado atual do ipset. Se você verificar o ipset manualmente e não encontrar o IP: - A entrada pode ter expirado (ipsets suportam tempos limites por entrada) - O cache do módulo (padrão 60s) pode mostrar uma entrada recentemente removida como ainda correspondida - Algo pode ter removido a entrada após a solicitação ser processada

Exemplos de Uso

Log de acesso 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;

Adicionar cabeçalhos para depuração:

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

Log condicional:

## Registrar apenas solicitações bloqueadas
map $ipset_result $loggable {
    "deny"  1;
    default 0;
}

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

📊 Métricas Prometheus

O endpoint /metrics retorna métricas no formato de exposição do Prometheus.

Métricas Disponíveis

## HELP nginx_ipset_requests_total Total de solicitações processadas
## 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 Operações de cache
## 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 cache atuais
## TYPE nginx_ipset_cache_entries gauge
nginx_ipset_cache_entries 5432

## HELP nginx_ipset_autoadd_total Operações de auto-adicionar
## 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 limite de taxa
## 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 desafio
## 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 Tempo de atividade do módulo
## TYPE nginx_ipset_uptime_seconds gauge
nginx_ipset_uptime_seconds 86400

Consultas do Dashboard Grafana

Taxa de solicitações por resultado:

rate(nginx_ipset_requests_total[5m])

Taxa de bloqueio:

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

Taxa de acerto de cache:

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

Gatilhos de limite de taxa por minuto:

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

📈 JSON Stats API

O endpoint /_stats retorna estatísticas detalhadas em formato JSON.

Formato de Resposta

{
  "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
  }
}

Descrições dos Campos

Campo Descrição
version Versão do módulo
uptime_seconds Segundos desde que o módulo foi carregado
requests.checked Total de solicitações processadas
requests.allowed Solicitações que passaram
requests.blocked Solicitações que foram bloqueadas
requests.errors Erros de pesquisa de ipset
cache.hits Acertos de cache (evitou chamada ao kernel)
cache.misses Erros de cache (chamada ao kernel necessária)
cache.entries Entradas em cache atuais
cache.hit_rate Percentual de acerto
autoadd.success Adições de honeypot bem-sucedidas
autoadd.failed Adições de honeypot falhadas
ratelimit.triggered Violações de limite de taxa
ratelimit.autobanned IPs auto-adicionados à lista de banimento
challenge.issued Páginas de desafio servidas
challenge.passed Desafios resolvidos com sucesso
challenge.failed Falhas de desafio
##

🏗️ Arquitetura

┌─────────────────────────────────────────────────────────────────────┐
│                           FLUXO DE SOLICITAÇÃO                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Solicitação de Entrada                                             │
│         │                                                            │
│         ▼                                                            │
│   ┌───────────────┐                                                  │
│   │  Verificação   │──── Excedido? ────▶ 429 + Auto-ban            │
│   │    de Taxa    │                                                  │
│   └───────┬───────┘                                                  │
│           │ OK                                                       │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Verificação  │──── Sem cookie? ────▶ Servir quebra-cabeça JS │
│   │    de Desafio  │                                                  │
│   └───────┬───────┘                                                  │
│           │ Aprovado                                                │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  Verificação  │────▶│   ACERTO    │────▶ Usar resultado em cache │
│   └───────┬───────┘     └─────────────┘                             │
│           │ FALHA                                                 │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  Consulta de   │──── Sessão libipset local por thread           │
│   │   ipset       │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ Armazenar em  │                                                  │
│   │    Cache      │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    Decisão    │──── Correspondência na lista negra? ────▶ Bloquear (403/444) │
│   │               │──── Falha na lista branca? ────▶ Bloquear (403/444) │
│   └───────┬───────┘                                                  │
│           │ Permitir                                                │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Verificação  │──── Correspondência na localização? ────▶ Adicionar ao ipset │
│   │    Honeypot   │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│       Continuar para                                              │
│       Manipulador de Conteúdo                                      │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                        MEMÓRIA COMPARTILHADA                        │
│  ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│  │     Estatísticas│    Cache LRU    │    Baldes de Limitação de Taxa│ │
│  │   (contadores)  │  (IP → Resultado)│   (IP → Contador de Solicitações)│ │
│  └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

Layout de Memória

Componente Localização Propósito
Sessão libipset Local por thread Sessão por worker para evitar bloqueios
Cache de pesquisa Memória compartilhada Cache LRU de mapeamentos IP→resultado
Baldes de limitação de taxa Memória compartilhada Contadores de solicitações por IP
Estatísticas Memória compartilhada Contadores atômicos para métricas
##

📚 Exemplos

Exemplo 1: Lista Negra Básica

## Criar 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;
    }
}

Exemplo 2: API com Limitação de Taxa

server {
    listen 80;

    # Limitação de taxa estrita para API
    ipset_ratelimit rate=100 window=1m autoban=api_banned ban_time=3600;

    # Permitir apenas parceiros conhecidos
    ipset_whitelist api_partners;
    ipset_status 401;

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

Exemplo 3: Pilha de Segurança Completa

    server {
        listen 80 default_server;

    # Camada 1: Ameaças conhecidas
    ipset_blacklist malware_ips tor_exits datacenter_ranges;
    ipset_status 444;
    ipset_cache_ttl 5m;

    # Camada 2: Limitação de taxa
    ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

    # Camada 3: Desafio para bots
    ipset_challenge on;
    ipset_challenge_difficulty 2;

    # Conteúdo real
        location / {
        root /var/www/html;
    }

    # Armadilhas honeypot - retornar 404 (padrão) para parecer arquivos ausentes
    location ~ ^/(wp-admin|phpmyadmin|admin)\.php$ {
        ipset_autoadd honeypot timeout=86400;
    }

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

Exemplo 4: Teste em Modo de Teste

server {
    listen 80;

    # Testar novas regras sem bloquear
    ipset_blacklist new_threat_list;
    ipset_dryrun on;

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

Verifique os logs:

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

🔧 Resolução de Problemas

Módulo não carregando

nginx: [emerg] dlopen() failed

Solução: Certifique-se de que o NGINX foi compilado com --with-compat e que o módulo foi compilado contra a mesma versão do NGINX.

ipset não encontrado

ipset: INVALID_SETNAME

Solução: Crie o ipset antes de iniciar o NGINX:

sudo ipset create myset hash:ip

Permissão negada

ipset: kernel error

Solução: O worker do NGINX precisa da capacidade CAP_NET_ADMIN:

sudo setcap cap_net_admin+ep /usr/sbin/nginx

Negativas do SELinux (RHEL/CentOS/AlmaLinux)

SELinux está impedindo /usr/sbin/nginx de acessar getattr no netlink_netfilter_socket

Solução: Instale o módulo de política SELinux incluído:

cd selinux/
sudo ./install.sh

Ou manualmente:

## Verificar
semodule -l | grep nginx_ipset

A política permite que httpd_t (domínio SELinux do NGINX) use sockets netlink_netfilter necessários pelo libipset.

Alto uso de memória

Solução: Reduza o TTL do cache ou limite o tamanho do cache na configuração de memória compartilhada.

Limitação de taxa não funcionando

Solução: Certifique-se de que o ipset para auto-banimento existe e tem suporte a tempo limite:

sudo ipset create ratelimited hash:ip timeout 3600

Log mostra "matched=setname" mas IP não está no ipset

Esse é um comportamento esperado. O módulo reporta o que viu no momento da solicitação. Se você verificar o ipset depois e não encontrar o IP:

  1. Expiração do tempo limite: O IP foi adicionado com um tempo limite e já expirou

    # Verifique se o conjunto suporta tempos limites
    ipset list setname | head -5
    # Procure por "timeout" no cabeçalho
    

  2. Cache do módulo: O módulo armazena em cache as pesquisas (padrão 60s). Um IP recentemente removido pode ainda aparecer como "correspondido"

    # Desativar temporariamente o cache para depuração (não para produção!)
    ipset_cache_ttl 0;
    

  3. Entrada foi removida: fail2ban, scripts ou comandos manuais podem ter removido

  4. Problema de configuração de armadilha: Se estiver usando armadilhas honeypot com ipset_autoadd, bots legítimos podem ter acionado armadilhas. Verifique se suas localizações de armadilha não se sobrepõem a caminhos legítimos de bots (como sitemaps, robots.txt). Use robots.txt para excluir caminhos de armadilha da indexação.

autoadd falha com "result=4"

Isso significa que você está usando timeout=N em ipset_autoadd, mas o ipset foi criado sem suporte a tempo limite.

Solução: Recrie o ipset com suporte a tempo limite:

## Usando ipset diretamente
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 (compilado com --with-compat)
  • Kernel Linux com suporte a ipset (módulo nf_tables ou xt_set)
  • Biblioteca libipset e cabeçalhos de desenvolvimento
  • Capacidades: CAP_NET_ADMIN para operações de ipset

📜 Licença

Este é um software proprietário. Todos os direitos reservados.

Disponível exclusivamente através do GetPageSpeed Premium Repository.

👤 Autor

Danila Vershinin
GetPageSpeed LLC

🆘 Suporte

Módulo de Acesso IPSet do NGINX
Um módulo premium do NGINX da GetPageSpeed LLC
www.getpagespeed.com