TL;DR
Мы перевели сервер управления Netbird VPN с Fail2Ban на CrowdSec, сократив «шум» от атак по SSH/HTTP на 99% и перейдя от реактивной модели (бан после 5 неудачных попыток) к превентивной (блокировка IP по коллективной разведке угроз ещё до того, как их трафик дойдёт до сервера).
В этой статье разбираем, почему мы на это решились и как вы можете сделать так же, с пошаговыми примерами кода.
Проблема: Fail2Ban в 2025 году
Десять лет Fail2Ban был золотым стандартом простого усиления защиты сервера. Настроил пару правил на регулярках, указал на /var/log/auth.log и считай, дело сделано. Но есть нюанс: по архитектуре Fail2Ban реактивен.
Почему Fail2Ban не справляется
1. Реактивность — это уязвимость
Fail2Ban похож на датчик дыма, который срабатывает только тогда, когда пожар уже разгорелся. Прежде чем правило включится, злоумышленнику нужно постучаться в ваш SSH-порт 5 и более раз. В мире распределённых ботнетов с 10 000+ IP-адресов это означает 50 000 бесплатных попыток прощупать вашу систему, прежде чем вы вообще заблокируете хотя бы один адрес.
Наши логи показывали одну и ту же картину: каждую ночь 500+ фальшивых SSH-рукопожатий с разных IP, каждое попадало в auth.log и съедало процессорное время на сопоставление по регулярным выражениям. Цель атакующего не в том, чтобы перебрать пароль (они понимают, что это бесполезно). Цель — составить карту вашей инфраструктуры, проверить открытые порты и зафиксировать ваши реакции, чтобы потом использовать это как оружие.
2. Проблема «силоса»: вы один
Fail2Ban полностью «слеп» к внешнему миру. Он работает в изоляции.
Реалистичный сценарий:
Один IP (скажем,
203.0.113.42) агрессивно сканирует 500 серверов по всей Европе одновременно.С Fail2Ban ваш сервер не знает, что этот адрес уже активничает на чужих серверах.
Вы пассивно ждёте, пока
203.0.113.42стукнется в ваш SSH-порт 5 раз.Тем временем он уже снял «отпечатки» 499 других серверов и вытащил данные как минимум со 100 из них.
С CrowdSec + CAPI (Community API):
Тот же IP пробует сервер во Франции (экземпляр CrowdSec №1).
Сканирует сервер в Германии (экземпляр №2).
Касается вашего сервера в Нидерландах (экземпляр №3).
За считанные секунды сообщество приходит к консенсусу: этот IP вредоносный.
Все 3 сервера (и ещё 8 000+ других, где запущен CrowdSec) блокируют его превентивно.
Вы больше не воюете в одиночку. Вы часть «Waze для кибербезопасности», где сигналы об угрозах распространяются по миру.
3. Ад регулярных выражений в эпоху JSON
Современные веб-серверы вроде Caddy пишут структурированные логи в JSON, а не простой текст. Сильная сторона Fail2Ban — разбор логов на регулярных выражениях — превращается в слабое место.
Реалистичный фильтр Fail2Ban для Caddy:
[Definition] failregex = ^(?P<host>\S+) - (?P<user>\S+) \[(?P<time>\d{2}/\w+/\d{4}:\d{2}:\d{2}:\d{2}) (?P<tz>[\+\-]\d{4})\] "(?P<method>\S+) (?P<uri>\S+) (?P<proto>\S+)" (?P<status>\d+) (?P<size>\S+) "(?P<referer>\S+)" "(?P<user_agent>\S+)" (?P<response_time>\d+)$
Это хрупкая конструкция. Стоит формату логов Caddy измениться (а с обновлениями такое бывает), и ваш фильтр ломается. Вместо нормальной защиты вы обслуживаете клубок экранирующих последовательностей, тогда как CrowdSec просто разбирает JSON «из коробки».
4. Нагрузка на CPU при масштабировании
Когда прилетает DDoS или просыпается ботнет, Python-демон Fail2Ban становится узким местом. Разбор логов + сопоставление по регулярным выражениям + принятие решений = всплески нагрузки на CPU. При этом CrowdSec на Go переваривает ту же нагрузку, потребляя в разы меньше ресурсов.
Решение: CrowdSec (философия и архитектура)
CrowdSec полностью переосмысливает обнаружение и предотвращение вторжений. Он отделяет обнаружение от реакции и вводит совместную «разведку» угроз.
Ключевые принципы
1. Коллективная разведка (CAPI)
CrowdSec работает так:
CrowdSec Security Engine на вашем сервере анализирует логи и выявляет подозрительные паттерны.
Когда достигается консенсус (IP попадает под несколько сценариев или помечается несколькими экземплярами), сигнал отправляется в Community API (CAPI).
Когда достаточное число независимых экземпляров помечает один и тот же IP, он попадает в общий блок-лист (Community Blocklist).
Ваш баунсер на уровне фаервола скачивает этот список и блокирует атакующих до того, как они успеют отправить пакеты.
Красота в том, что вы используете коллективный интеллект 10 000+ администраторов. Вам не нужно ждать, пока ваш сервер атакуют 5 раз, вы получаете раннее предупреждение за счёт сетевого эффекта.
2. Развязанная архитектура
В отличие от монолитного дизайна Fail2Ban, CrowdSec разделяет зоны ответственности:
┌──────────────────────────────────────────┐ │ CrowdSec Security Engine (Go) │ │ - Парсит логи │ │ - Сопоставляет сценарии │ │ - Принимает решения │ └──────────┬───────────────────────────────┘ │ (Local API) ┌──────────┴────────────────────────────────┐ │ │ ┌─────▼──────────────┐ ┌────────────▼──────────────┐ │ Firewall Bouncer │ │ HTTP Bouncer (WAF) │ │ (nftables/iptables) │ (Блокировка на L7) │ └────────────────────┘ └───────────────────────────┘
Вы сами решаете, где блокировать:
Уровень фаервола (nftables): самый быстрый и эффективный вариант. Пакеты отбрасываются до того, как начнут потреблять ресурсы.
Уровень HTTP (L7): можно применять бизнес-логику. Блокировать по заголовкам, путям и т. п.
Уровень приложения: кастомные ответы, логирование, ограничение скорости запросов.
Мы выбрали блокировку на уровне фаервола (nftables), потому что для «закалённого» сервера управления VPN это самый эффективный вариант.
3. Обнаружение на основе сценариев (а не просто подсчёт)
Fail2Ban считает неудачные попытки. CrowdSec понимает контекст.
Пример сценария: HTTP-сканирование
name: crowdsecurity/http-crawl-non_statics description: "Обнаруживает агрессивный обход не статических ресурсов" filter: - http_status: [404] # Много 404 обычно означает сканирование - user_agent: [scrapy, nikto, sqlmap] # Известные инструменты сканирования - request_uri: !~ /\.(jpg|css|js|png)$/ # Не статические ресурсы detection: - trigger: > (count(events) > 20) && (duration < 5m) && (user_agent matches malicious_patterns) action: ban
Разница:
Fail2Ban: «5 неудачных попыток по SSH = бан»
CrowdSec: «20 ответов 404 за 5 минут + подозрительный User-Agent = вероятно, сканер. Проверяем, отмечали ли этот IP другие экземпляры. Если да, консенсус достигнут, значит бан».
Наша инфраструк��ура: Netbird + Caddy + CrowdSec
Общий обзор системы
Интернет-трафик ↓ ┌──────────────────────────────────────┐ │ nftables (файрвол) │ │ ├─ правила CrowdSec (DROP вредоносных) │ └─ SSH (порт 2222) │ └──────────────────────────────────────┘ ↓ ┌──────────────────────────────────────┐ │ Caddy обратный прокси │ │ ├─ завершение TLS │ │ ├─ JSON access-логи → CrowdSec │ │ └─ проксирование в Netbird (8080) │ └──────────────────────────────────────┘ ↓ API управления Netbird VPN
ОС и версии
ОС: Ubuntu 24.04 LTS (Noble Numbat)
CrowdSec: v1.6+
Caddy: последняя версия (сборка из исходников или пакет)
Файрвол: nftables (по умолчанию в Ubuntu 24.04)
Bouncer: crowdsec-firewall-bouncer-nftables
Реализация: код
Шаг 1: Установка CrowdSec
# Добавить репозиторий curl -s https://install.crowdsec.net | sudo sh sudo apt update # Установить security engine sudo apt install -y crowdsec # Установить коллекции (SSH, syslog и т. д.) sudo cscli collections install crowdsecurity/linux sudo cscli collections install crowdsecurity/caddy-logs sudo systemctl reload crowdsec
Шаг 2: Настройка Caddy на JSON-логирование
Парсер Caddy в CrowdSec ожидает логи в JSON. Настройте Caddyfile:
{ log { output file /var/log/caddy/access.log { roll_size 100mb roll_keep 5 roll_keep_for 720h } format json level info } } # Ваш обратный прокси netbird.example.com { encode gzip reverse_proxy localhost:8080 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} } }
Перезапустите Caddy:
sudo systemctl restart caddy
Проверьте JSON-вывод:
sudo tail -f /var/log/caddy/access.log | jq '.' | head -20
Шаг 3: Настройка CrowdSec на разбор логов Caddy
Создайте /etc/crowdsec/acquis.d/caddy.yaml:
filenames: - /var/log/caddy/access.log labels: type: caddy
Перезагрузите CrowdSec:
sudo systemctl reload crowdsec
Проверьте разбор логов:
sudo cscli metrics show acquisition # Ожидаемый вывод: # crowdsecurity/caddy-logs │ 1234 │ 0 │ 0 │ 0 │ 0 │ 1234
Шаг 4: Установка баунсера для фаервола (nftables)
sudo apt install -y crowdsec-firewall-bouncer-nftables sudo systemctl enable crowdsec-firewall-bouncer sudo systemctl start crowdsec-firewall-bouncer
Проверьте, что баунсер зарегистрирован:
sudo cscli bouncers list # Ожидаемый вывод: # Name: crowdsec-firewall-bouncer-nftables # Status: ✓ active
Шаг 5: Настройка длительности бана
По умолчанию CrowdSec банит на 4 часа. Мы увеличили срок до 48 часов для «упорных» ботнетов:
Создайте /etc/crowdsec/profiles.yaml.local:
name: default debug: false rules: - type: ban duration: 48h notifications: []
Перезагрузите:
sudo systemctl reload crowdsec
Результаты и метрики
После миграции мы увидели следующее:
Метрики
sudo cscli metrics show
Вывод (снимок):
Acquisition (читаемые логи): crowdsecurity/caddy-logs: 12,450 lines | 0 parse errors crowdsecurity/sshd-logs: 5,230 lines | 0 parse errors Scenarios (правила обнаружения): crowdsecurity/http-crawl-non_statics: 142 decisions | 28 IPs banned crowdsecurity/ssh-bf: 89 decisions | 15 IPs banned crowdsecurity/web-application-attacks: 34 decisions | 8 IPs banned Bouncers: crowdsec-firewall-bouncer-nftables: 112 active bans
Ключевые наблюдения
Снижение «шума» в логах на 99%: до CrowdSec файл /var/log/auth.log разрастался до 2 ГБ в день (SSH-пробы). Теперь около 20 МБ в день. Почему? IP блокируются на уровне фаервола, пакеты даже не доходят до sshd.
Эффективность блок-листа сообщества: из 112 активных банов 95+ пришли из общего блок-листа сообщества. Мы даже не видели первичную атаку, CrowdSec через CAPI блокировал её превентивно.
Разбор JSON-логов Caddy: ноль ошибок парсинга. CrowdSec без проблем переживал изменения формата логов (JSON сам себя описывает).
Влияние на CPU: CrowdSec Security Engine стабильно держался в районе 2–5% CPU. Логи Caddy разбирались в реальном времени без заметной нагрузки.
Практические наблюдения
Мониторинг и отладка
Проверить активные баны:
sudo cscli decisions list # Output: # Duration │ Scope │ Value │ Decision │ Reason # 48h │ ip │ 192.0.2.100 │ ban │ crowdsecurity/http-crawl-non_statics # 48h │ ip │ 198.51.100.42 │ ban │ crowdsecurity/ssh-bf
Посмотреть алерты (почему были приняты решения):
sudo cscli alerts list --ip 192.0.2.100 # Output: # Alert ID: 4521 # Start Time: 2025-12-31T10:15:30Z # End Time: 2025-12-31T10:20:45Z # Scenario: crowdsecurity/http-crawl-non_statics # Events Count: 145 # Remediation: ban for 48h
Мониторинг nftables в реальном времени:
# Посмотреть, как отбрасываются пакеты sudo nft monitor # Или проверить статистику sudo nft list ruleset | grep -A 10 "crowdsec-drop" # Пример: # chain crowdsec-drop (priority filter -1; policy accept;) # packets 28,432 bytes 1,842,560
Выводы из опыта
Общий блок-лист сообщества на вес золота. В 99% случаев мы блокировали угрозы ещё до того, как они касались нашей инфраструктуры.
JSON-логирование не обсуждается. Если вы используете современный веб-сервер (Caddy, Nginx с JSON-выводом и т. д.), сделайте себе одолжение и включите его. Разбор логов на регулярках это технология вчерашнего дня.
По производительности Go лучше Python. Движок CrowdSec на Go достаточно быстрый, чтобы на скромном сервере разбирать 10 000+ строк логов в секунду. Fail2Ban на таком бы захлебнулся.
Баунсеры гибкие. Мы выбрали nftables, но CrowdSec поддерживает HTTP-баунсеры (L7), модули для Nginx, интеграции с облачными API (Cloudflare, AWS) и многое другое. Выбирайте то, что подходит вашей архитектуре.
Возможные проблемы и решения
Проблема: баунсер не проходит аутентификацию
Симптом: в статусе crowdsec-firewall-bouncer отображается «offline» или «error».
Решение:
# Пересоздать учётные данные sudo apt reinstall -y crowdsec-firewall-bouncer-nftables # Перезапустить оба сервиса sudo systemctl restart crowdsec sudo systemctl restart crowdsec-firewall-bouncer # Проверить sudo cscli bouncers list
Проблема: решения не принимаются
Симптом: cscli decisions list возвращает пустой результат.
Решение:
1. Проверьте, что логи читаются:
sudo cscli metrics show acquisition
Если счётчики стоят на месте, CrowdSec не читает логи.
2. Проверьте права на файл:
ls -la /var/log/caddy/access.log # у пользователя crowdsec должны быть права на чтение
3. Перезагрузите CrowdSec:
sudo systemctl reload crowdsec
Проблема: ложные срабатывания (заблокирован легитимный трафик)
Симптом: пользователи жалуются, что доступ закрыт, хотя они легитимны.
Решение:
Добавьте их в белый список:
sudo cscli decisions add --ip 203.0.113.99 --duration 0 --type whitelist
Или временно отключите конкретный сценарий:
sudo cscli scenarios disable crowdsecurity/http-crawl-non_statics
Выводы и рекомендации
Почему мы рекомендуем CrowdSec для продакшена
Безопасность: превентивная защита лучше реактивной. Вас прикрывает коллективный интеллект 10 000+ экземпляров.
Простота эксплуатации: разбор JSON, развязанные баунсеры, богатые дашборды.
Производительность: движок на Go, минимальная нагрузка на CPU, масштабируется до 10 000+ правил.
Прозрачность: open-source, управляется сообществом, удобно для аудита.
Следующие шаги
Автоматизируйте резервное копирование
/etc/crowdsec/на случай аварийного восстановления.Настройте дашборды на console.crowdsec.net, чтобы визуализировать угрозы по всему вашему парку серверов.
Включите уведомления (Slack, email) для критичных алертов.
Дотюньте сценарии, подбирая пороги и длительность банов под ваш кейс.
Интегрируйте с вашей SIEM-системой (ELK, Splunk и т. д.) для централизованного логирования.

Если вы устали латать дыры точечно и хотите выстроить безопасность как часть инженерного процесса, это уже территория DevSecOps. На курсе «Внедрение и работа в DevSecOps» разбираем, как встраивать threat modeling, SAST, WAF, защиту API и мониторинг/реагирование (SIEM) в CI/CD — от архитектуры до продакшена. Чтобы узнать, подойдет ли вам программа курса, пройдите вступительный тест.
Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:
16 февраля, 20:00. «Roadmap внедрения DevSecOps. Роли, цели, сроки». Записаться
17 февраля, 20:00. «Основы безопасности в Kubernetes». Записаться
19 февраля, 20:00. «DDoS-инцидент: как действует CISO». Записаться
