Abra o access.log e conte quantos meses de IP completo de visitante estão ali. IP é dado pessoal na LGPD, e ninguém no time usa o octeto final: relatório de região, contagem de acesso e bloqueio por bot funcionam igual com 203.0.113.0. Guardar o número inteiro é risco sem contrapartida.
Um map e um formato de log novo
O bloco vai dentro de http, no /etc/nginx/nginx.conf, antes dos includes dos sites. O map cobre IPv4 e IPv6 e só é avaliado quando a variável aparece no log:
map $remote_addr $ip_anon {
~(?P<ip>d+.d+.d+). "$ip.0";
~(?P<ip>[^:]+:[^:]+): "$ip::";
default "0.0.0.0";
}
log_format lgpd '$ip_anon - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log lgpd;O IPv4 perde o último octeto e o IPv6 fica com os dois primeiros grupos, o que basta para saber a operadora sem identificar a linha. Rode sudo nginx -t antes do sudo systemctl reload nginx.
Não mate o fail2ban junto
Essa é a parte que quebra em silêncio: o fail2ban lê o IP do log para banir e, com tudo mascarado, passa a banir 203.0.113.0 ou nada. A saída é um segundo log com IP real e vida curta. Repare na herança: um access_log declarado no server block substitui o do http, então as duas linhas precisam estar lá dentro.
# no server block do site, as duas linhas
access_log /var/log/nginx/access.log lgpd;
access_log /var/log/nginx/seguranca.log combined;
# /etc/fail2ban/jail.local — comentário só em linha própria
[nginx-4xx]
enabled = true
filter = nginx-4xx
logpath = /var/log/nginx/seguranca.log
maxretry = 20
findtime = 5mCrie um /etc/logrotate.d/nginx-seguranca com daily e rotate 3 para esse arquivo. Três dias resolvem investigação de ataque e você para de acumular histórico que teria de justificar num pedido de titular.