Если вы не используете в своей работе Bash-сценарии - то вы не используете и половины возможностей своей unix-подобной операционной системы. В этой статье реч...
Блог компании 3v-Hosting
8 мин.
Многие владельцы сайтов вздыхают с облегчением, как только включают Cloudflare. Такие функции, как фильтрация трафика, защита от DDoS-атак и пограничное кэширование, делают инфраструктуру любого проекта более устойчивой. Однако есть один тонкий нюанс, который заключается в том, что CloudFlare скрывает реальные IP-адреса посетителей вашего сайта, в том числе и злоумышленников. В итоге, когда ваш сервер видит только IP-адреса CloudFlare, то такие инструменты, как например Fail2ban, не могут блокировать определенных клиентов по IP адресу.
Представьте, что ваш сайт на WordPress подвергается брутфорс-атакам на страницу /wp-login.php. Cloudflare проксирует все эти запросы, но ваш конечный сервер видит только несколько IP-адресов, которые принадлежат узлам Cloudflare, которые делают десятки запросов. И если в таком случае Fail2ban блокирует их, то он случайно блокирует и весь легитимный трафик. Это как закрыть всю станцию метро из-за того, что туда проник один карманник - по факту не самая умная стратегия:)
Тогда возникает правомерный вопрос: Так как-же сделать Fail2ban снова полезным, когда сайт находится за CloudFlare? Об этом и поговорим в данной статье.
Fail2ban - это такой сторожевой механизм, который проверяет логи вашего сервера и отыскивает в них подозрительные паттерны поведения пользователей, такие как неудачные попытки входа по SSH, чрезмерное количество запросов к какой либо странице и повторяющиеся ошибки в логах доступа Nginx. Если количество таких нарушений с какого либо IP адреса превышает определенный предел, то Fail2ban добавляет нарушивший правила IP-адрес в правила брандмауэра на вашем сервере.
Например, если кто-то совершает 20 неудачных попыток входа по SSH на ваш сервер в течение одной минуты, то Fail2ban вставляет правило в iptables, чтобы заблокировать соединения с этого IP-адреса.
Однако, если вы используете CloudFlare, то сервер не может видеть реальный IP адрес посетителя, а только его "маску" в виде IP-адреса самого CloudFlare. То есть каждый запрос к вашему серверу поступает из инфраструктуры CloudFlare. Вместо компьютера злоумышленника (203.0.113.45) в журналах вы видите дата-центр CloudFlare (172.71.150.2).
Если Fail2ban заблокирует этот адрес, он заблокирует сам CloudFlare, отрезав тысячи невинных пользователей вместе с злоумышленником.
Решением является настройка вашего веб-сервера и Fail2ban для идентификации реального IP-адреса клиента и его блокировки. Здесь в игру вступают HTTP-заголовки и немного магии настройки.
В данном примере мы будем приводить все настройки применительно к веб-серверу Nginx, но если вы используете другой веб-сервер, например Apache, то в нём подобный функционал также можно легко реализовать.
Итак, CloudFlare добавляет к каждому запросу, который он проксирует на ваш сервер, заголовок X-Forwarded-For или CF-Connecting-IP. Этот заголовок содержит фактический адрес клиента, который вы можете увидеть, настроив веб-сервер так, чтобы он доверял этому заголовку.
В Nginx вам понадобится модуль real_ip. Для его включения создайте файл, например /etc/nginx/conf.d/cloudflare_realip.conf, и добавьте в него такую конфигурацию:
real_ip_header CF-Connecting-IP; set_real_ip_from 173.245.48.0/20; set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 108.162.192.0/18; set_real_ip_from 190.93.240.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 162.158.0.0/15; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 172.64.0.0/13; set_real_ip_from 131.0.72.0/22; set_real_ip_from 2400:cb00::/32; set_real_ip_from 2606:4700::/32; set_real_ip_from 2803:f800::/32; set_real_ip_from 2405:b500::/32; set_real_ip_from 2405:8100::/32; set_real_ip_from 2a06:98c0::/29; set_real_ip_from 2c0f:f248::/32; real_ip_recursive on;
Как вы видите, в файле мы указали все публичные IPv4 и IPv6 адреса самого Cloudflare. Теперь ваш сервер, видя, что запрос пришёл с одного из этих IP адресов, будет проверять заголовок X-Forwarded-For, беря из него информацию о реальном IP-адресе посетителя. Таким образом в логах веб-сервера будет отображаться реальный IP-адрес посетителя. Для точности всегда используйте полный список подсетей CloudFlare, доступный на странице документации.
И тут, казалось-бы, бери да блокируй эти адреса в случае нарушений правил. Но если бы всё было так просто, мы бы эту статьи не писали. Давайте обсудим чуть глубже, как работает Cloudflare.
Когда вы настроили свой веб-сервер для получения реальных IP-адресов посетителей из заголовков X-Forwarded-For, веб-сервер читает эти заголовки и в лог складывает эти реальные IP адреса, по каждому запросу. Но сам трафик фактически продолжает приходить на ваш сервер всё под теми же IP адресами Cloudflare.
То есть представьте, что вы получили письмо от Шарлиз Терон на свою электронную почту, открыли его, а в тексте самого письма написано "отправитель Джим Керри". Да, вы теперь знаете, что письмо переслали и что его фактическим составителем является Джим, но получили то вы его от Шарлиз, с его почтового адреса. И если вы заблокируете адрес Джима, то с адреса Шарлиз вам продолжат поступать шутливые письма :)
Простите за такой яркий пример, но суть, я думаю, вы уловили.
Что же делать в таком случае?
Ответ тут очевиден, нужно блокировать реальный IP адрес отправителя на стороне Cloudflare, чтобы они даже не пытались проксировать запросы от этого пользователя к вам на сервер.
Вы спросите, как же это сделать?
Сделать это оказывается достаточно просто, хотя и придётся слегка повозиться. Но сам механизм существует и он достаточно хорошо работает. Для этого нам понадобится связка вашего обычно Fail2ban с API самого Cloudflare.
Когда доходишь до идеи переноса блокировки на сторону Cloudflare, то возникает логичный вопрос, как именно блокировать? В Cloudflare для этого есть как минимум два варианта:
Первый - это так называемые IP Access Rules. По сути, это простые правила вида "заблокировать этот IP". Они создаются по одному, вручную или через API, и работают на уровне аккаунта или зоны.
На первый взгляд кажется, что это именно то, что нужно. Fail2ban обнаружил нарушителя, после чего создал правило, которое блокирует его по IP адресу. Но на практике этот подход довольно быстро перестает быть удобным.
Представь типичную ситуацию, когда боты начинают сканировать ваш сайт, в результате чего Fail2ban за сутки ловит несколько сотен или тысяч адресов. Если для каждого из них создавать отдельное правило, то через неделю у тебя в Cloudflare будут уже тысячи записей. Интерфейс, в таком случае, превращается в свалку, управлять этим становится неудобно и сложно, а любые массовые операции, например банальная очистка, становится отдельной болью.
Кроме того, этот метод довольно плохо масштабируется, ведь Fail2ban - инструмент автоматический и он может добавлять десятки или сотни IP в час. А модель "одно правило - один IP" для таких сценариев просто не предназначена.
Именно поэтому гораздо более правильный путь - это использование Custom Lists в сочетании с одним WAF-правилом (Web Application Firewall).
Смысл здесь очень простой. Ты создаёшь один список IP-адресов, например fail2ban-blocklist, а дальше создаёшь лишь одно правило в WAF, которое говорит:
если IP клиента находится в этом списке - блокируй запрос от него.
В итоге у тебя в интерфейсе всего один список, в который добавляются IP и одно правило, которое на него ссылается. А Fail2ban уже просто управляет содержимым этого списка. И такой подход даёт сразу несколько практических преимуществ.
Во-первых, это банально выглядит чище. У тебя нет тысячи разрозненных правил, которые заменяются одним аккуратным списком.
Во-вторых, этим удобно управлять. Можно посмотреть список целиком, выгрузить его, почистить, отфильтровать, а не ковыряться в длинной ленте правил.
В-третьих, этот метод легко масштабируется, так как добавление нового IP - это просто запись в список, а не создание нового объекта в системе правил.
Ну и, наконец, сам Cloudflare рекомендует использовать свой WAF, а им-то виднее как лучше :)
Когда понимаешь общую идею, то сама настройка оказывается довольно нативной. Но важно сделать её аккуратно, как и любую другую работу, чтобы потом не ловить побочные эффекты.
Начинается всё с создания API-токена, через который Fail2ban будет общаться с Cloudflare.
В панели Cloudflare нужно перейти в профиль, раздел API Tokens, и создать новый токен. В целях безопасности, лучше не давать ему много прав, поэтому прописываем только самое необходимое:
Этот токен будет лежать на сервере, и его не стоит делать всемогущим, на всякий случай.
После этого создаётся сам список.
В интерфейсе Cloudflare это делается в разделе WAF → Tools → Lists. Нужно создать новый список IP-адресов и дать ему понятное имя, например:
fail2ban-blocklist
На этом этапе список пока пустой и это абсолютно нормально, ведь заполнять его будет Fail2ban, когда мы его настроим.
Дальше создаётся ключевой элемент всей нашей схемы - WAF правило. Это правило максимально простое по своей логике:
ip.src in $fail2ban-blocklist
Поле Action: Block
То есть оно гласит, что если IP источника запроса находится в нашем списке, тогда применить к нему действие Block.
Именно это правило связывает всё воедино и без него список сам по себе ничего не делает.
Всё, на этом настройка Cloudflare закончена и мы можем переходить к настройке Fail2ban.
После того как мы перенесли точку блокировки на сторону Cloudflare, сам Fail2ban никуда не исчезает, он остаётся центральным элементом всей схемы. Просто его роль становится чуть другой. Теперь он не блокирует трафик напрямую, а только принимает решение о том, кто является нарушителем, после чего передаёт это решение дальше - в Cloudflare.
Приступим.
Здесь, что важно, ничего принципиально нового не появляется. Мы по прежнему всё так же описываем:
Например, защита стандартной страницы логина WordPress может выглядеть приблизительно так:
[wordpress-login] enabled = true port = http,https filter = wordpress-login logpath = /var/log/nginx/access.log maxretry = 5 findtime = 600 bantime = 3600 ignoreip = 127.0.0.1/8 YOUR_IP YOUR_SUBNET
Здесь мы описали, что если за 10 минут было больше 5 неудачных попыток логина, то мы считаем IP подозрительным. Итак, на этом этапе мы научили Fail2ban находить злоумышленников.
ВАЖНО! В последней строке мы указали параметр ignoreip, который обязательно рекомендуем вам использовать, чтобы ненароком не заблокировать себя самого.
Вот здесь начинается отличие от классической схемы. Напомним, что по умолчанию Fail2ban при бане добавляет блокирующее правило в iptables. Но в нашей архитектуре это бессмысленно и выше мы уже разобрали почему.
Поэтому мы заменяем стандартный action на свой, который будет работать через API Cloudflare.
Проще всего создать отдельный action-файл, например /etc/fail2ban/action.d/cloudflare.conf, внутри которого мы опишем то, что делать при блокировке и при разблокировке пользователя. Соответственно при блокировке мы добавляем IP в список Cloudflare, а при разблокировке - удаляем IP из этого списка.
Простейший пример может выглядеть так:
[Definition]
# API
_cf_account_id = {{ YOUR ACCOUNT ID }}
_cf_list_id = {{ YOUR WAF LIST ID }}
_cf_api_prms = -H "Authorization: Bearer {{ YOUR TOKEN }}" -H "Content-Type: application/json"
# Actions
actionstart =
actionstop =
actioncheck =
# BAN → добавляем IP в list
actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/<_cf_account_id>/rules/lists/<_cf_list_id>/items" \
<_cf_api_prms> \
--data '[{"ip":"<ip>","comment":"fail2ban"}]'
# UNBAN → удаляем IP из list
actionunban = ITEM_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/<_cf_account_id>/rules/lists/<_cf_list_id>/items" \
<_cf_api_prms> | jq -r '.result[] | select(.ip=="<ip>") | .id'); \
[ -n "$ITEM_ID" ] && curl -s -X DELETE "https://api.cloudflare.com/client/v4/accounts/<_cf_account_id>/rules/lists/<_cf_list_id>/items" \
<_cf_api_prms> \
--data "{\"items\":[{\"id\":\"$ITEM_ID\"}]}"
Это минимальный вариант, но его вполне достаточно, чтобы понять механику и начать первые блокировки нежелательных соединений.
На практике такие action’ы часто дорабатывают, например добавляя проверки успешности ответов API, логирование ошибок и т.п. Но суть от этого не меняется - Fail2ban превращается в клиента Cloudflare API.
Помните наш jail, который мы создали выше? Так вот после того как action описан, его нужно подключить к нашему jail. А делается это одной строкой:
action = cloudflare
То есть наш Jail стал выглядеть так:
[wordpress-login] enabled = true port = http,https filter = wordpress-login logpath = /var/log/nginx/access.log maxretry = 5 findtime = 600 bantime = 3600 ignoreip = 127.0.0.1/8 YOUR_IP YOUR_SUBNET action = cloudflare
Перезагружаем Fail2ban с помощью команды
systemctl restart fail2ban
и с этого момента Fail2ban перестаёт трогать локальный firewall и начинает работать через Cloudflare.
Как после выполнения любой работы, работу нужно проверить.
Сначала протестируем принудительную блокировку. Наберите в консоли сервера команду:
fail2ban-client set wordpress-login banip 1.2.3.4
После этого нужно убедиться в трёх вещах:
Затем обязательно тестируем разблокировку:
fail2ban-client set wordpress-login unbanip 1.2.3.4
И проверяем, что IP удален из листа, а доступ для него вернулся.
Только после этого можно считать, что схема реально работает.
И последнее, что важно зафиксировать, чтобы не было путаницы. Вся эта конструкция нужна именно для HTTP/HTTPS-трафика, который идёт через Cloudflare.
Для других сервисов, таких, например, как SSH - ничего не меняется. Ведь в их случае:
Поэтому не нужно пытаться "натянуть Cloudflare" на всё подряд.
После того как все настройки были произведены, а сервис Fail2ban был перезагружен, наша схема начинает полноценную работу. Кратко резюмируем её ещё раз:
fail2ban-blocklist;При разблокировке происходит всё то же самое, только в обратную сторону.
С точки зрения бизнеса, неспособность защитить ваш сайт от атак методом перебора - это не только повышение нагрузки на процессор вашего сервера. Постоянные попытки генерируют ошибки, раздувают журналы и могут замедлять работу уровней кэширования. Время отклика сервера имеет решающее значение для SEO, так как Googlebot не будет ждать вечно и может просто прекратить обход вашего сайта. Более того, если сервер перегружен запросами злоумышленников и страницы вашего сайта открываются медленно и с задержками, то ваш сайт вовсе может попасть под пессимизацию в выдаче, как не прошедший тесты PageSpeed Insights.
Например, владелец одного интернет-магазина заметил, что боты атаковали /wp-login.php сотни раз в минуту. Страницы начали загружаться медленно, и клиенты бросали свои корзины. После настройки Fail2ban с помощью заголовков Cloudflare нагрузка на сервер нормализовалась, и коэффициент конверсии восстановился.
В этом случае безопасность напрямую влияет на продажи.
Почему Fail2ban не блокирует IP, хотя в логах всё видно правильно? Потому что лог и сеть - это разные уровни. После настройки real IP nginx показывает реальный адрес клиента, но соединение до сервера всё равно приходит от Cloudflare. Fail2ban передаёт IP в firewall, а тот просто не видит такого источника. В результате бан есть, но на трафик он не влияет.
Можно ли всё-таки использовать iptables вместе с Cloudflare? Можно, но не для HTTP/HTTPS. Локальный firewall остаётся актуальным для SSH и других сервисов, которые идут напрямую. Просто не стоит ожидать от него блокировки клиентов, которые приходят через Cloudflare.
Зачем вообще нужен Fail2ban, если есть Cloudflare WAF? Cloudflare не знает контекста вашего приложения. Он не понимает, что для вас является подозрительным поведением, например перебор пароля в админке. Fail2ban как раз это и делает, а Cloudflare уже применяет блокировку.
Почему нельзя просто создавать IP Access Rules вместо списков? Можно, но это быстро превращается в хаос. При активной атаке появятся сотни правил, с которыми неудобно работать. Список и одно правило дают ту же функциональность, но без лишнего мусора.
Что будет, если случайно заблокировать свой IP? Вы просто перестанете попадать на сайт, потому что блокировка произойдёт на стороне Cloudflare. Поэтому лучше сразу добавить свои IP в исключения, чтобы не ловить такие ситуации в самый неподходящий момент.
Насколько безопасно использовать API token Cloudflare на сервере? Это нормально, если дать ему только необходимые права и не хранить его где попало. По сути это доступ к управлению блокировками, поэтому относиться к нему нужно аккуратно и при малейших сомнениях перевыпускать.
Подойдёт ли это только для WordPress или для любого сайта? Это универсальный подход. WordPress просто удобный пример, но схема работает для любого сайта, где есть логи HTTP-запросов и можно описать, что считать подозрительным поведением.
Когда начинаешь настраивать Fail2ban за Cloudflare, кажется, что достаточно просто "вернуть" реальные IP в логи и всё снова будет работать как раньше. Формально это правда, определение злоумышленника начинает работать корректно. Но на практике этого недостаточно, потому что меняется сама точка, где нужно применять блокировку.
Главное, к чему приходишь на основе реального опыта, что в архитектуре с reverse proxy нельзя слепо переносить старые подходы. Если трафик проходит через Cloudflare, то и управлять им нужно там же. Попытка блокировать клиентов локально через iptables в этом случае даёт только иллюзию защиты.
Правильная схема оказывается довольно простой и логичной: Fail2ban остаётся инструментом анализа и принятия решения, а Cloudflare тем местом, где это решение реализуется. Как только разделяешь эти роли, как сразу исчезают все странные эффекты вроде того, что блокировка есть, а атака продолжается.
В итоге реализуется не обходное решение, а более зрелая архитектура, когда внешний слой фильтрует трафик на входе, а внутренний слой понимает поведение и контекст. И именно в такой связке система начинает работать стабильно, предсказуемо и без неприятных сюрпризов.
Отдельно хотим выразить глубокую благодарность нашему читателю, который дал полезную обратную связь, позволившую откорректировать данную статью. Думаем он узнает себя:) Спасибо!
Установка и настройка Nginx на AlmaLinux 9: команды, запуск, firewall, конфиги, virtual host и частые ошибки. Пошаговая инструкция для быстрого старта и стабиль...
Как изменились кибератаки в 2025-2026 и почему под ударом оказались VPS, выделенные серверы и хостинг в целом. Разбираем реальные сценарии атак и что это значит...
Что такое UFW, его особенности и преимущества. Разбираем базовую настройку файервола в Linux: логика правил, открытие портов, управление доступом и типичные оши...