Делать будем на примере панельки vestacp со стандартной связкой nginx + apache. В принципе различий между настройками в иных панельках особо нет, за исключением некоторых моментов с размещением лог файлов и конфигураций nginx или apache.
Цимес заключается в том, что если ваш сайт подключен через cloudflare, то http соединения с вашим сервером происходят от серверов cloudflare. Однако при этом в логах вы видите реальный ip клиента. И даже если вы внесете в бан файрвола на своем сервере любой ip из своих логов, эти клиенты всё равно будут подключаться без проблем. Как же это происходит? Загляните в свой /etc/nginx.conf и сразу поймете:
# Cloudflare https://www.cloudflare.com/ips
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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
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 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;
real_ip_header CF-Connecting-IP;
IP клиента передается в заголовке CF-Connecting-IP, его и пишет в лог ваш сервер при соединении с данными подсетями сервиса cloudflare. Кстати по ссылке вы можете увидеть все эти подсети.
Следовательно, банить клинтов нужно используя не только файрвол сервера, а также в первую очередь банить через файрвол cloudflare передавая ему по api конфигурацию бана. Для этого в директории /etc/fail2ban/action.d/ создадим соответствующий конфиг действий cloudflare.conf Кстати там уже есть данный файл, но он использует старое api, так что можно смело писать в него новый конфиг такого содержания:
#
# To get your Cloudflare API key: https://www.cloudflare.com/my-account
#
[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart =
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop =
# Option: actioncheck
# Notes.: command executed once before each actionban command
# Values: CMD
#
actioncheck =
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: IP address
# number of failures
# unix timestamp of the ban time
# Values: CMD
actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" \
-H "X-Auth-Email: <cfuser>" \
-H "X-Auth-Key: <cftoken>" \
-H "Content-Type: application/json" \
--data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"Fail2ban"}'
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: IP address
# number of failures
# unix timestamp of the ban time
# Values: CMD
#
actionunban = curl -s -o /dev/null -X DELETE -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \
https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$(curl -s -X GET -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \
'https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1' | tr -d '\n' | cut -d'"' -f6)
[Init]
# Option: cfuser
# Notes.: Replaces <cfuser> in actionban and actionunban with cfuser value below
# Values: Your CloudFlare user account
cfuser = YOU_MAIL
# Option: cftoken
# Notes.: Replaces <cftoken> in actionban and actionunban with cftoken value below
# Values: Your CloudFlare API key
cftoken = YOU_API_TOKEN
свой api токен вы можете посмотреть в профиле аккаунта cloudflare

Теперь в директории /etc/fail2ban/filter.d/ создадим фильтр с названием http-ddos.conf и таким содержимым:
# Fail2Ban configuration file [Definition] # Option: failregex # Note: This regex will match any GET and POST entry in your logs, so basically all valid and not valid entries are a match. # You should set up in the jail.conf file, the maxretry and findtime carefully in order to avoid false positives. failregex = ^<HOST> -.*"(GET|POST|CONNECT|HEAD).* # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
А в директории /etc/fail2ban/jail.d/ создадим конфиг http-ddos.conf
[http-ddos]
enabled = true
filter = http-ddos
action = cloudflare
iptables-multiport[name=http-ddos, port="http,https", protocol=tcp]
port = http,https
logpath = /var/log/apache2/domains/*com.log
/var/log/apache2/domains/*ru.log
findtime = 60
bantime = 86400
maxretry = 1200
С шаблонами логов тут пришлось немного извратиться, поскольку vesta не добавляет access в названиях файлов. А там лежат ещё error логи, которые в данном случае, нам не нужны. А как прописать шаблон с исключением в данном конфиге я не знаю, ведь это не обычная регулярка. Можно конечно настраивать локально CustomLog в дерективах апача для каждого сайта и задать любые названия лог файлов с любыми префиксами, но тогда логи не просматриваются из панельки. И нужно тогда пилить ещё и панельку на строке:
/usr/local/vesta/data/templates/web/apache2/default.tpl:12: CustomLog /var/log/%web_system%/domains/%domain%.log combined
Решил не заморачиваться и добавить шаблоны по доменным зонам.
- findtime — это время в секундах по которому будет просматриваться совпадения
- bantime — время бана
- maxretry — максимальное количество совпадений за указанный период, после которого наступает банэ
Эти параметры нужно настраивать внимательно и индивидуально, чтобы не забанить лишних юзеров.
И теперь, для того, чтобы каждого клиента fail2ban не писал в свой лог, поменяем loglevel в файле /etc/fail2ban/fail2ban.conf указав loglevel = NOTICE По умолчанию там стоит INFO и в лог пишется каждое совпадение с шаблоном.
Выполним fail2ban-client -d для проверки конфигураций.
В vestacp ротация логов apache почему-то настроена в еженедельном режиме weekly. Это не есть хорошо и может сказаться на производительности при анализе fail2ban-ом больших файлов. Этот режим необходимо поменять на daily в файле /etc/logrotate.d/apache2 Если есть большие лог файлы на данный момент их нужно удалить и перезапустить апач. Теперь перезапустим сервис systemctl restart fail2ban
Все подключенные джайлы можем видеть по команде fail2ban-client status Всех забаненных по нашему вновь созданному файлу можем видеть по команде fail2ban-client status http-ddos а также в панельке cloudflare во вкладке firewall тут:

Бан и разбан происходит как на уровне iptables сервера, а также отправляется в бан файрвола сервиса cloudflare.