Блог компанії 3v-Hosting

Налаштування захисту Fail2ban для сайту за CloudFlare

Адміністрування

8 хв.


Багато власників сайтів зітхають з полегшенням, щойно вмикають Cloudflare. Такі функції, як фільтрація трафіку, захист від DDoS-атак та прикордонне кешування, роблять інфраструктуру будь-якого проєкту більш стійкою. Однак є один тонкий нюанс, який полягає в тому, що CloudFlare приховує реальні IP-адреси відвідувачів вашого сайту, в тому числі й зловмисників. У підсумку, коли ваш сервер бачить лише IP-адреси CloudFlare, такі інструменти, як, наприклад, Fail2ban, не можуть блокувати певних клієнтів за IP-адресою.

Уявіть, що ваш сайт на WordPress піддається брутфорс-атакам на сторінку /wp-login.php. Cloudflare проксірує всі ці запити, але ваш кінцевий сервер бачить лише кілька IP-адрес, які належать вузлам Cloudflare, що роблять десятки запитів. І якщо в такому випадку Fail2ban блокує їх, то він випадково блокує і весь легітимний трафік. Це як закрити всю станцію метро через те, що туди проник один кишеньковий злодій - фактично не найрозумніша стратегія :)

Тоді виникає слушне запитання: як же зробити Fail2ban знову корисним, коли сайт знаходиться за CloudFlare? Про це й поговоримо в цій статті.

 

 

 

 

Як 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-заголовки та трохи магії налаштування.

 

 

 

 

Налаштування веб-сервера для визначення реальної IP-адреси

 

У цьому прикладі ми наводимо всі налаштування стосовно веб-сервера Nginx, але якщо ви використовуєте інший веб-сервер, наприклад Apache, то в ньому подібну функціональність також можна легко реалізувати.

Отже, CloudFlare додає до кожного запиту, який він проксірує на ваш сервер, заголовок X-Forwarded-For або CF-Connecting-IP. Цей заголовок містить фактичну адресу клієнта, яку ви можете побачити, налаштувавши веб-сервер так, щоб він довіряв цьому заголовку.

 

Приклад налаштування Nginx

У 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.

 

 

 

 

Як працює Cloudflare "під капотом"

Коли ви налаштували свій веб-сервер для отримання реальних IP-адрес відвідувачів із заголовків X-Forwarded-For, веб-сервер зчитує ці заголовки та записує ці реальні IP-адреси в лог за кожним запитом. Але сам трафік фактично продовжує надходити на ваш сервер під тими самими IP-адресами Cloudflare.

Тобто уявіть, що ви отримали лист від Шарліз Терон на свою електронну пошту, відкрили його, а в тексті самого листа написано "відправник Джим Керрі". Так, ви тепер знаєте, що лист переслали і що його фактичним автором є Джим, але отримали його ви від Шарліз, з її поштової адреси. І якщо ви заблокуєте адресу Джима, то з адреси Шарліз вам продовжать надходити жартівливі листи :)

Вибачте за такий яскравий приклад, але суть, я думаю, ви вловили.

 

Що ж робити в такому випадку?

Відповідь тут очевидна, потрібно блокувати реальну IP-адресу відправника на стороні Cloudflare, щоб вони навіть не намагалися проксірувати запити від цього користувача до вашого сервера.

 

Ви запитаєте, як же це зробити?

Зробити це виявляється досить просто, хоча й доведеться трохи повозитися. Але сам механізм існує і він досить добре працює. Для цього нам знадобиться зв'язка вашого, зазвичай, Fail2ban з API самого Cloudflare.

 

 

 

Налаштування 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, і створити новий токен. З міркувань безпеки краще не надавати йому багато прав, тому прописуємо тільки найнеобхідніше:

  • доступ до управління WAF (Firewall Services);
  • доступ до списків (Lists).

Цей токен буде зберігатися на сервері, і його не варто робити всемогутнім, про всяк випадок.

 

Після цього створюється сам список.

В інтерфейсі Cloudflare це робиться в розділі WAF → Tools → Lists. Потрібно створити новий список IP-адрес і дати йому зрозумілу назву, наприклад:

fail2ban-blocklist

На цьому етапі список поки що порожній, і це абсолютно нормально, адже заповнювати його буде Fail2ban, коли ми його налаштуємо.

 

Далі створюється ключовий елемент усієї нашої схеми - правило WAF. Це правило максимально просте за своєю логікою:

ip.src in $fail2ban-blocklist

Поле Action: Block

 

Тобто воно говорить, що якщо IP джерела запиту знаходиться в нашому списку, тоді застосувати до нього дію Block.

Саме це правило пов'язує все воєдино і без нього список сам по собі нічого не робить.

Все, на цьому налаштування Cloudflare закінчено і ми можемо переходити до налаштування Fail2ban.

 

 

 

 

Налаштування Fail2ban

Після того як ми перенесли точку блокування на сторону Cloudflare, сам Fail2ban нікуди не зникає, він залишається центральним елементом всієї схеми. Просто його роль стає трохи іншою. Тепер він не блокує трафік безпосередньо, а лише приймає рішення про те, хто є порушником, після чого передає це рішення далі - в Cloudflare.

Приступимо.

 

Базове налаштування jail

Тут, що важливо, нічого принципово нового не з'являється. Ми, як і раніше, все так само описуємо:

  • що вважаємо порушенням;
  • скільки спроб допускаємо;
  • за який період;
  • і на який термін потрібно банити.

 

Наприклад, захист стандартної сторінки входу в 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, який обов'язково рекомендуємо вам використовувати, щоб ненароком не заблокувати себе самого.

 

 

Налаштування action

Ось тут починається відмінність від класичної схеми. Нагадаємо, що за замовчуванням 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.

 

 

 

Підключення action

Пам'ятаєте наш 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

 

Після цього потрібно переконатися у трьох речах:

  • IP 1.2.3.4 з'явився в custom list у Cloudflare;
  • правило WAF його дійсно блокує;
  • запити з цього IP перестали доходити до сервера (так, так, можете підставити будь-який тестовий IP)

 

Потім обов'язково тестуємо розблокування:

fail2ban-client set wordpress-login unbanip 1.2.3.4

 

І перевіряємо, що IP видалено зі списку, а доступ для нього повернувся.

Тільки після цього можна вважати, що схема реально працює.

 

 

 

Важливо!

І останнє, що важливо зафіксувати, щоб не було плутанини. Вся ця конструкція потрібна саме для HTTP/HTTPS-трафіку, який проходить через Cloudflare.

Для інших сервісів, таких, наприклад, як SSH - нічого не змінюється. Адже в їхньому випадку:

  • з'єднання йде безпосередньо на IP-адресу вашого сервера;
  • Fail2ban працює за звичайною схемою, через iptables;
  • блокування відбувається локально на вашому сервері.

 

Тому не потрібно намагатися "натягнути Cloudflare" на все підряд.

 

 

 

 

Підсумуємо, як це починає працювати

Після того як всі налаштування були зроблені, а сервіс Fail2ban був перезавантажений, наша схема починає повноцінну роботу. Коротко резюмуємо її ще раз:

  • Fail2ban знаходить зловмисника в логах вашого веб-сервера;
  • замість додавання правила в локальний iptables він робить HTTP-запит до API Cloudflare;
  • додає IP зловмисника до fail2ban-blocklist;
  • Cloudflare одразу ж починає блокувати цей IP.

Під час розблокування відбувається те саме, тільки у зворотному напрямку.

 

 

 

 

 

SEO та перспективи цифрового бізнесу

 

З точки зору бізнесу, нездатність захистити ваш сайт від атак методом перебору - це не лише підвищення навантаження на процесор вашого сервера. Постійні спроби генерують помилки, роздувають журнали та можуть уповільнювати роботу рівнів кешування.

Час відгуку сервера має вирішальне значення для SEO, оскільки Googlebot не чекатиме вічно і може просто припинити обхід вашого сайту. Більше того, якщо сервер перевантажений запитами зловмисників і сторінки вашого сайту відкриваються повільно та із затримками, то ваш сайт взагалі може потрапити під песимізацію у видачі, як такий, що не пройшов тести PageSpeed Insights.

Наприклад, власник одного інтернет-магазину помітив, що боти атакували /wp-login.php сотні разів на хвилину. Сторінки почали завантажуватися повільно, і клієнти кидали свої кошики. Після налаштування Fail2ban за допомогою заголовків Cloudflare навантаження на сервер нормалізувалося, і коефіцієнт конверсії відновився.

У цьому випадку безпека безпосередньо впливає на продажі.

 

 

 

 

FAQ

Чому 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 - тим місцем, де це рішення реалізується. Як тільки розділяєш ці ролі, одразу зникають усі дивні ефекти на кшталт того, що блокування є, а атака триває.

У підсумку реалізується не обхідне рішення, а більш зріла архітектура, коли зовнішній шар фільтрує трафік на вході, а внутрішній шар розуміє поведінку та контекст. І саме в такій комбінації система починає працювати стабільно, передбачувано і без неприємних сюрпризів.

 

Окремо хочемо висловити глибоку вдячність нашому читачеві, який надав корисний відгук, що дозволив скоригувати цю статтю. Гадаємо, він впізнає себе :) Дякуємо!

3v-Hosting Team

Автор

3v-Hosting Team

Команда 3v-Hosting складається з групи відданих своїй справі інженерів та операторів, які повністю присвятили себе створенню та підтримці основи наших сервісів. Щодня ми занурюємося у світ віртуальних та виділених серверів, займаючись усім, від розгортання та моніторингу до усунення реальних проблем, що виникають у виробничих середовищах. Більшість наших статей ґрунтуються на практичному досвіді, а не лише на теорії. Ми ділимося своїми думками щодо викликів, з якими стикаємося: перебоїв у роботі, помилок у налаштуваннях, складнощів мережевої взаємодії та архітектурних рішень, що впливають на стабільність і надійність. Наша місія проста - ми хочемо ділитися знаннями, які допоможуть вам керувати своїми проектами з меншою кількістю несподіванок та набагато більшою передбачуваністю.

Встановлення Nginx на AlmaLinux 9
Встановлення Nginx на AlmaLinux 9

Встановлення та налаштування Nginx на AlmaLinux 9: команди, запуск, брандмауер, конфігураційні файли, віртуальні хости та типові помилки. Покрокова інструкція д...

8 хв