
O servidor sobe de CPU do nada e o access.log está entupido de POST /wp-login.php. Plugin de limite de tentativas não resolve esse caso: ele só age depois que o PHP montou o WordPress inteiro, e é justamente esse carregamento que está comendo o processador. O corte tem que ser no nginx.
A zona vive no bloco http e é compartilhada por todos os sites. Dez megabytes seguram algo perto de 160 mil endereços:
# em /etc/nginx/nginx.conf, dentro de http { }
limit_req_zone $binary_remote_addr zone=login:10m rate=2r/m;
# no server { } do site
location = /wp-login.php {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
} O rate=2r/m libera uma requisição a cada 30 segundos por IP. O burst=3 guarda três excedentes numa fila e o nodelay manda essas três na hora, em vez de segurar. Quem passar disso leva 429 e nunca encosta no FPM.
A requisição barrada aparece sim no access.log, com status 429 (campo 9 no formato combined). O motivo, com IP e nome da zona, o nginx joga no log de erro, porque limit_req_log_level vem em error por padrão:
sudo nginx -t && sudo systemctl reload nginx
sudo awk '$9 == 429' /var/log/nginx/access.log | tail -20
sudo grep "limiting requests" /var/log/nginx/error.log | tail -20 Duas pegadinhas. A primeira: location = /wp-login.php é match exato e vence o location ~ .php$, então se você esquecer o fastcgi_pass ali dentro o nginx passa a oferecer o arquivo como download e a tela de login some. A segunda: atrás de Cloudflare ou de um balanceador, $binary_remote_addr é o IP do proxy, e sem o módulo real_ip configurado você limita todo mundo de uma vez.
Deixe rodando um dia e releia o error.log. Se aparecer IP de gente de verdade sendo cortada, afrouxe pra 5r/m.
Seu access.log guarda o IP inteiro dos visitantes há meses sem necessidade. Mascare o último octeto com map e log_format…
A observação do pedido chegou com ordem embutida para gerar cupom. Delimite o texto do cliente e trate a resposta…
Um CSV com SKU e preço, um wp eval-file que agenda início e fim da promoção guardando o estado anterior,…
O erro 1040 aparece quando todas as conexões estão ocupadas. Antes de subir o max_connections, veja quem está segurando cada…
Allowed memory size exhausted no painel: qual das duas constantes do wp-config.php mexer, onde conferir o valor real e por…
strtotime com data brasileira devolve false e o INSERT quebra no MySQL 8. Use createFromFormat com getLastErrors antes de mandar…