Как заблокировать диапазон IP-адресов? "Screened IPs" не блокируются

Привет! Я пытаюсь временно заблокировать abusive подсеть /16, которая обрушивает форум Discourse запросами. Я попробовал это…

…но всё ещё вижу огромное количество новых запросов из того же диапазона в /var/discourse/shared/standalone/log/var-log/nginx/access.log.

Поскольку эти настройки конфигурируются в Discourse, я почти уверен, что IP-адреса блокируются именно Discourse, а не NGINX, поэтому они будут отображаться в логах NGINX. Блокировку осуществляет Discourse, а не nginx. Если вы хотите заблокировать их так, чтобы они не появлялись в логах NGINX, вы можете сделать это с помощью вашего фаервола.

Спасибо, Джей, вы правы: если блокировка происходит на уровне приложения, запросы всё равно будут отображаться в логах Nginx. Однако и блокировка на уровне приложения работает не так, как я ожидал. Я подключился через VPN, добавил свой IP-адрес в список «Screened IPs», но форум всё равно был доступен для навигации. Думаю, этот список называется «Screened IPs», а не «Blocked IPs», потому что, возможно, он лишь предотвращает регистрацию аккаунтов с этих адресов.

Мне нужно, чтобы приложение Discourse отказывало в доступе к запрошенным страницам для запросов, приходящих с этих адресов, и, что особенно важно, не отображало эти страницы, поскольку все такие запросы перегружают процессор.

Видит ли Discourse, что вы зашли с одного из запрещённых IP-адресов, если вы просматриваете запись пользователя через /admin/users? (Если вы находитесь за прокси, например Cloudflare, то Discourse может видеть IP-адрес вашего прокси, а не IP-адрес пользователя.)

Да, когда я подключаюсь к VPN, а затем смотрю последний IP-адрес моего учётной записи в Discourse, там отображается IP, который предоставил мне VPN. Однако, когда я открываю окно браузера в режиме инкогнито и пытаюсь зарегистрировать новую учётную запись, это не удаётся:

Новые регистрации не разрешены с вашего IP-адреса.

Похоже, что «отфильтрованные IP-адреса» применяются только для регистрации, а не для полного запрета доступа к сайту.

Чтобы ещё больше усложнить ситуацию, ufw / nftables на хост-сервере, похоже, не блокирует соединения так, как ожидалось, внутри Docker:

Не уверен, где мы это документируем, но этот вопрос уже несколько раз поднимался в последнее время.

Функция «отфильтрованные IP-адреса» блокирует регистрацию и вход с заблокированных IP-адресов, которые совпадают с правилами, но не прерывает существующие сеансы.

Не уверен, есть ли у нас документация по этому вопросу (и если да, то где).

Спасибо за подтверждение.

Так какой же самый простой способ запретить запросы с определённого IP или диапазона IP-адресов? Я нашёл это, но, похоже, это обратное тому, что мне нужно (белый список вместо чёрного), а возиться с конфигурацией Nginx внутри контейнера кажется полным криворуким решением:

Я думаю, что лучше всего это сделать с помощью UFW или IPTABLES. Это остановит запросы ещё до того, как в дело вступит Discourse. Я всегда немного боюсь возиться с фаерволами, опасаясь заблокировать себя, но если вы настроите правило только для порта 443, то никакой опасности нет.

У Digital Ocean есть несколько подсказок: https://www.digitalocean.com/community/tutorials/ufw-essentials-common-firewall-rules-and-commands. Я бы просто поискал примеры в Google.

Именно этого я тоже боюсь. Но я включил его на хосте, и всё равно он не блокирует проблемный диапазон IP-адресов. Похоже, для того чтобы правила запрета применились к контейнерам Docker, требуется сложный набор правил.

О, да. Это совершенно верно. В итоге я заблокировал доступ с моих веб-серверов на базе Docker к базе данных PostgreSQL, работающей в контейнере Docker (скорее всего, это не ваша проблема).

Вот ещё одна идея: Geo Blocking plugin

Спасибо, я тоже смотрел на него, но, похоже, он не позволяет блокировать диапазоны числовых IP-адресов, только целые страны?

Я не устанавливал это недавно, но я почти уверен, что такая возможность есть.

(выделение добавлено)

Однако потом я нашел это:

Так что, я думаю, это означает, что вы можете указать там любую сеть, которую захотите.

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

В блоке server { добавьте:

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

Затем сохраните и выполните:

nginx -t
service nginx reload

Я не до конца понимаю, почему в access.log Nginx всё ещё видны запросы с 12.34.x.x, но похоже, что это сработало, так как загрузка процессора снова пришла в норму. По-моему, процесс невероятно запутанный, но на данный этого достаточно, чтобы вернуть сайт к жизни.

Да, но сейчас он принимает только номера автономных систем (AS) и не поддерживает обозначение CIDR, например 1.2.3.0/24.

Это сработало? Мне кажется, вам нужно выполнить

sv restart nginx

Но если вы не получили ошибку, то я ошибаюсь.

Nginx всё ещё видит их? Показывает ли он, что обслуживает их? Видите ли вы их в rails production.log?

Ах. Возможно, мне следовало уделить больше внимания той странице в Википедии о номерах автономных систем.

Думаю, это оба устаревших алиаса, которые теперь сопоставлены с командами systemd, поэтому systemctl restart nginx было бы наиболее правильным.
РЕДАКТИРОВАНИЕ: Похоже, что systemctl не работает внутри Docker. Вот несколько объяснений различий:

Да, в access.log они всё ещё появляются так:

[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 "-" "-" "-" "-" "-" "-" "-"

Кажется, они в основном атакуют постоянные ссылки (перенесённые со старой платформы форума). Есть ли какая-то лазейка с постоянными ссылками, позволяющая обойти правило deny? Я ещё не проверял production.log.

В целом я бы сказал, что отсутствие графического интерфейса для просмотра логов доступа и блокировки IP-адресов на уровне приложения является существенным ограничением Discourse. Это случается нечасто, но когда вы сталкиваетесь с одной из таких атак ботов/скраперов/краулеров, вы хотите немедленно определить источник и нейтрализовать его, не копаясь в куче конфигурационных файлов и архаичных командах, особенно не заходя на несколько уровней глубже внутрь контейнера Docker со всеми его странными абстракциями. Очень старая платформа форума, с которой я мигрировал, показывала простой список пользователей или IP-адресов с наибольшим количеством запросов за настраиваемый промежуток времени, и её можно было даже отфильтровать по тем пользователям и/или IP-адресам, которые занимали наибольшее время процессора. Таким образом, я мог быстро определить проблемный адрес или диапазон, а затем через интерфейс «клик-и-нажми» добавить его в чёрный список, после чего запросы от этих IP-адресов получали ответ 404.

Проблемы нет.

Если у вас есть правило deny, запросы всё равно записываются в логи nginx. И это работает корректно, поскольку там указан статус 403, что означает отказ в доступе для клиента.

Эти запросы не перенаправляются в Discourse. Если вы хотите проверить, правильно ли работает ваша блокировка, вам следует либо

  • посмотреть в production.log Discourse,
  • либо проверить логи nginx, игнорируя любые записи, где в поле кода HTTP-ответа указан 403.

Эта тема уже решена? Есть ли один пост от @rgj или @pfaffman, который я могу отметить как решение? Похоже, вы работали над этим вместе!

:handshake:

Привет! Я бы сказал, что в настоящее время эту проблему нельзя решить «стандартными» методами. Интерфейс администратора для «отфильтрованных IP-адресов» не работает так, как ожидают большинство пользователей, а метод, который действительно работает, требует редактирования конфигурационных файлов внутри Docker-контейнера Discourse. Поэтому это скорее грязный обходной путь, чем решение, по крайней мере, на мой взгляд. Было бы здорово, если бы это привлекло больше внимания: