Como bloquear um intervalo de IPs?

Olá, estou tentando bloquear temporariamente uma sub-rede /16 abusiva que está sobrecarregando um fórum Discourse com solicitações. Tentei isto…

…mas ainda estou vendo um grande número de novas solicitações da mesma faixa em /var/discourse/shared/standalone/log/var-log/nginx/access.log.

Como estes estão configurados no Discourse, tenho certeza de que os IPs são bloqueados pelo Discourse, não pelo NGINX, então eles aparecerão nos logs do NGINX. É o Discourse que os está bloqueando, não o nginx. Se você quiser bloqueá-los para que não apareçam nos logs do NGINX, você pode bloqueá-los com seu firewall.

1 curtida

Obrigado Jay, você está certo sobre como ainda apareceria nos logs do Nginx se bloqueado no nível do aplicativo. No entanto, o bloqueio no nível do aplicativo também não está fazendo o que eu esperaria. Tentei me conectar via VPN e então adicionei meu próprio endereço IP à lista de "IPs em Quarentena", mas ainda assim me permitiu navegar pelo fórum. Acho que deve ser chamado de "IPs em Quarentena" e não "IPs Bloqueados" porque talvez ele apenas impeça que esses IPs registrem uma conta?

O que eu preciso é que o aplicativo Discourse negue o acesso às páginas solicitadas para requisições vindas desses endereços e, especialmente, que ele não renderize essas páginas, já que todas essas requisições estão sobrecarregando a CPU.

O Discourse vê que você está vindo de um dos IPs banidos se você for ver o registro do usuário em /admin/users? (Se você estiver atrás de um proxy como o Cloudflare, o Discourse pode estar vendo o IP do seu proxy e não o IP do usuário.)

Sim, quando me conecto à VPN e depois olho o último IP da minha conta de usuário no Discourse, ele mostra o IP que minha VPN me deu. No entanto, quando abro uma janela anônima do navegador e tento registrar uma nova conta, ele não permite:

Novos registros não são permitidos a partir do seu endereço IP.

Portanto, parece que os “IPs verificados” são apenas para registro, não para impedir completamente o acesso ao site.

E para complicar ainda mais as coisas, o ufw no servidor host aparentemente não bloqueia as coisas como esperado dentro do Docker:

1 curtida

Não tenho certeza onde documentamos isso, mas surgiu algumas vezes recentemente.

“IPs Filtrados” bloqueia registros e logins de IPs bloqueados que correspondem, mas não sessões existentes.

Não tenho certeza onde (se é que) documentamos isso.

3 curtidas

Obrigado por confirmar.

Então, qual seria o método mais fácil para negar solicitações de um IP ou intervalo de IPs? Encontrei isto, mas parece ser o oposto do que preciso. (lista branca em vez de lista negra) e mexer na configuração do Nginx dentro do contêiner parece um trabalho totalmente improvisado:

Eu acho que fazer isso com UFW ou IPTABLES. Isso remove, para antes que o Discourse se envolva. Eu sempre tenho um medo vago de mexer com firewalls por medo de me bloquear, mas se você mirar apenas na porta 443, não há perigo.

O Digital Ocean tem algumas dicas: UFW Essentials: Common Firewall Rules and Commands for Linux Security | DigitalOcean. Eu apenas pesquisaria por exemplos.

Exatamente o meu medo também. Mas eu o ativei no host e, ainda assim, ele não está bloqueando a faixa de IP problemática. Aparentemente, ele precisa de um conjunto complicado de regras para fazer com que as regras de negação se apliquem aos contêineres Docker.

Ah. Sim. Isso é totalmente verdade. Acabei bloqueando o acesso dos meus servidores web baseados em Docker ao banco de dados postgres baseado em Docker (provavelmente não é um dos seus problemas).

Aqui está outra ideia: Geo Blocking plugin

Obrigado, eu também estava olhando para isso, mas ele não parece permitir o bloqueio de intervalos de IP numéricos, apenas países inteiros?

Não o instalei recentemente, mas tenho quase certeza de que ele permite.

(ênfase adicionada)

Mas então encontrei isto:

Então, acho que isso significa que você pode colocar qualquer rede que quiser lá.

1 curtida
/var/discourse/launcher enter app
apt install nano
nano /etc/nginx/conf.d/discourse.conf

E no bloco server { adicione:

## 2025-10-27
deny 12.34.0.0/16;

Em seguida, salve e

nginx -t
service nginx reload

Não entendo bem por que ainda estou vendo acessos de 12.34.x.x no access.log do Nginx, mas parece estar funcionando porque o uso da CPU voltou ao normal. Processo incrivelmente complicado, na minha opinião, mas bom o suficiente por enquanto para colocar o site de volta nos trilhos.

Sim, mas atualmente ele só aceita números AS e não notação CIDR como 1.2.3.0/24.

1 curtida

Isso funcionou? Acho que você precisa fazer

sv restart nginx

Mas se você não teve um erro, eu estou errado.

O Nginx ainda está vendo esses? Ele mostra que está servindo eles? Você vê isso no production.log do Rails?

Ah. Talvez eu devesse ter prestado mais atenção naquela página da Wikipédia sobre números AS.

Acho que ambos são aliases antigos que agora estão mapeados para comandos systemd, então systemctl restart nginx seria o mais correto.
EDIT: Aparentemente, systemctl não funciona dentro do Docker. Aqui estão algumas explicações sobre as diferenças:

Sim, no access.log eles ainda aparecem como:

[28/Oct/2025:00:29:27 +0000] "myforum.com" 12.34.56.78 "GET /permalink/12345 HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" "-" 403 691 "-" - 0.000 "-" "-" "-" "-" "-" "-" "-"

Eles parecem estar principalmente acessando permalinks agora (migrados de uma plataforma de fórum antiga). Existe algum tipo de brecha com permalinks que permite contornar a regra deny? Eu ainda não verifiquei o production.log.

No geral, eu diria que a falta de uma GUI para inspecionar os logs de acesso e nenhuma lista de bloqueio de IP no nível do aplicativo é uma limitação bastante significativa do Discourse. É uma ocorrência infrequente, mas quando você é atingido por um desses ataques de bot/scraper/crawler, você só quer identificar a origem imediatamente e mitigá-la, sem mexer em um monte de arquivos de configuração e comandos arcanos, especialmente não em níveis profundos dentro de um contêiner Docker com toda a abstração estranha que ocorre lá. A plataforma de fórum muito antiga da qual migrei mostrava uma lista simples dos usuários ou IPs com o maior número de requisições durante uma janela de tempo ajustável, e podia até ser filtrada por quais usuários e/ou IPs ocupavam a maior quantidade de tempo de CPU. Dessa forma, eu poderia identificar rapidamente o endereço ou intervalo ofensivo, e então havia uma interface de apontar e clicar para adicioná-lo a uma lista de bloqueio, e ele retornaria um 404 para requisições desses IPs.

Se você tiver uma regra deny, as coisas ainda são registradas no nginx. E funciona corretamente, porque há um 403 lá, o que significa que o cliente teve o acesso negado.

Essas requisições não estão sendo encaminhadas para o Discourse. Se você quiser saber se o seu bloqueio está funcionando corretamente, você deve ou

  • olhar no production.log do Discourse em vez disso
  • olhar nos logs do nginx, mas ignorar qualquer entrada que tenha um 403 no campo do código de resposta HTTP.
3 curtidas

Este tópico está resolvido agora? Há alguma postagem de @rgj ou @pfaffman que eu possa escolher como solução? Parece que vocês colaboraram nesta!

:handshake:

Olá, eu diria que este problema não é realmente solucionável no momento por métodos “normais”. A interface de administração para “Screened IPs” não faz o que a maioria dos usuários provavelmente esperaria, e o método que realmente funciona envolve mexer dentro do contêiner docker do Discourse, então é mais como um hack sujo do que uma solução, pelo menos na minha humilde opinião. Seria ótimo se isso ganhasse um pouco mais de tração: