CrowdSec на VPS: колективний fail2ban для SSH, Nginx і Docker
TL;DR
CrowdSec встановлюється на VPS як демон аналізу логів: він виявляє підозрілу активність у SSH, Nginx і контейнерах Docker, а потім через firewall-bouncer блокує шкідливі IP-адреси. На відміну від класичного fail2ban, CrowdSec може використовувати колективну репутацію IP, але рішення про блокування та застосування санкцій залишаються на вашому сервері.
- Для невеликого production-сервера достатньо 2 vCPU, 2–4 ГБ RAM і 40–80 ГБ SSD.
- Буде налаштовано SSH, Nginx, Docker-логи та firewall-bouncer для nftables.
- Для HTTPS використовується Caddy з автоматичним отриманням сертифікатів Let’s Encrypt.
- Конфігурація CrowdSec зберігається окремо від файлів, що автоматично оновлюються.
- Наприкінці буде налаштовано перевірку, резервне копіювання, оновлення та діагностику типових помилок.
1. TL;DR
CrowdSec — сучасна система виявлення та блокування атак, яку часто називають колективним fail2ban. Вона читає системні та прикладні логи, застосовує сценарії виявлення й передає рішення firewall-bouncer. У результаті перебір SSH-паролів, сканування Nginx і частина атак на Docker-сервіси блокуються до того, як зловмисник отримає багато спроб.
Ані CrowdSec, ані fail2ban не замінюють оновлення, SSH-ключі, мінімальні права та правильну публікацію Docker-портів. Основна мета цієї інструкції — отримати багаторівневий захист одного VPS без встановлення окремої керівної платформи.
- Операційна система: Debian 12 або Ubuntu Server 24.04 LTS.
- CrowdSec: гілка 1.6.x, актуальна стабільна гілка на 2026 рік.
- Reverse proxy: Nginx 1.26+ або Caddy 2.9+; у прикладі використовуються обидва компоненти за різними сценаріями.
- Фаєрвол: nftables через firewall-bouncer.
- Docker Engine: актуальна стабільна гілка 27/28, встановлена з офіційного репозиторію Docker.
2. Зміст
Інструкція розрахована на чистий VPS із публічною IPv4-адресою. Команди наведено для Debian 12 і Ubuntu 24.04; назви пакетів і шляхи в цих системах практично однакові.
Якщо на сервері вже працюють Nginx, Docker або fail2ban, перед встановленням збережіть їхню конфігурацію. Особливо важливо перевірити, які порти опубліковані Docker-контейнерами: публікація порту через Docker може обходити звичайні правила ufw, тому для production краще контролювати доступ на рівні Docker, nftables і reverse proxy.
- Спочатку створюється окремий адміністратор і обмежується SSH.
- Потім встановлюються базові компоненти та CrowdSec.
- Після цього підключаються колекції сценаріїв для Linux, SSH, Nginx і Docker.
- Вмикається firewall-bouncer, який перетворює рішення CrowdSec на реальні блокування.
- Виконується тестування логів, сценаріїв, firewall і HTTPS.
3. Що ми налаштовуємо і навіщо
Як працює CrowdSec
CrowdSec складається з кількох логічних частин. Local API зберігає рішення та приймає події від security engine. Engine читає логи, передає рядки парсерам і сценаріям, а сценарії визначають поведінку: перебір паролів, сканування шляхів, велику кількість помилок або ознаки відомого exploit-патерну.
Після спрацьовування сценарію з’являється рішення, наприклад блокування IP на чотири години. Bouncer отримує це рішення та застосовує його до вхідного трафіку. Для Linux із nftables це зазвичай окремий ланцюжок у netfilter, тому вебсерверу не потрібно самостійно реалізовувати блокування.
| Компонент | Призначення | Що перевіряти |
|---|---|---|
| Security engine | Читає логи та запускає сценарії | cscli metrics |
| Парсери | Перетворюють рядки журналів на події | cscli hub list |
| Scenarios | Визначають підозрілі послідовності | cscli scenarios list |
| Firewall-bouncer | Блокує IP через nftables | cscli bouncers list |
| Central API | Публікує та отримує колективну репутацію | Статус реєстрації та pull |
Чому це не просто заміна fail2ban
Fail2ban зазвичай аналізує лише локальні логи та створює локальне правило блокування. Це добре працює проти повторюваних атак на конкретний сервер. CrowdSec додає єдиний рушій сценаріїв, зручне керування колекціями та можливість використовувати сигнали від інших інсталяцій через Central API.
Колективна репутація не означає, що кожна адреса автоматично вважається небезпечною назавжди. Рішення мають тип, джерело та строк дії. Адміністратор може переглянути рішення, видалити його або додати власне. Для критичних систем рекомендується спочатку ввімкнути спостереження та перевірити false positive, а потім розширювати блокування.
Що буде захищено
- SSH: перебір паролів, велика кількість невдалих підключень, спроби сканування.
- Nginx: масові запити до неіснуючих шляхів, підозрілі URL і деякі відомі шаблони атак.
- Docker: захист не контейнера самого по собі, а логів застосунків і reverse proxy. Якщо застосунок записує корисні події в stdout, їх можна збирати через Docker logging driver або файл.
- Системний firewall: блокування IP на рівні ядра, до обробки запитів застосунком.
Self-hosted і cloud-managed варіанти
Cloud-managed WAF, CDN і security gateway зручні, коли потрібно захищати багато доменів, розподіляти трафік за регіонами або автоматично фільтрувати volumetric DDoS. За це доводиться платити щомісяця, спрямовувати DNS через сторонню мережу та приймати обмеження провайдера.
Self-hosted CrowdSec на VPS підходить для одного сервера, невеликої команди, private API, Git-сервера, панелі адміністрування та застосунків, де важливий повний контроль над логами. Водночас VPS не здатен зупинити велику DDoS-атаку: якщо забитий канал або віртуальний NIC провайдера, локальний firewall уже не допоможе.
4. Яка VPS-конфігурація потрібна для цього завдання
CrowdSec споживає небагато CPU та пам’яті. Основне навантаження залежить не від самого агента, а від обсягу логів, кількості сценаріїв, швидкості запитів Nginx і кількості контейнерів. Для SSH та одного сайту вимоги мінімальні; для кількох застосунків потрібно враховувати їхнє власне споживання RAM.
| Сценарій | CPU | RAM | Диск | Мережа |
|---|---|---|---|---|
| SSH і невеликий Nginx | 1 vCPU | 1 ГБ | 20–30 ГБ SSD | 100 Мбіт/с |
| Docker, 2–5 сервісів і CrowdSec | 2 vCPU | 4 ГБ | 60–80 ГБ NVMe | 1 Гбіт/с |
| Кілька сайтів і CI-завдання | 4 vCPU | 8 ГБ | 100–160 ГБ NVMe | 1 Гбіт/с |
Практичний варіант для більшості встановлень
Для цього посібника розумно взяти 2 vCPU, 4 ГБ RAM, 60–80 ГБ NVMe, одну публічну IPv4-адресу та порт 1 Гбіт/с. Такий запас дає змогу одночасно запустити CrowdSec, Nginx або Caddy, Docker Compose і кілька невеликих застосунків. Якщо контейнери використовують PostgreSQL, Elasticsearch, GitLab або складання образів, RAM слід збільшити окремо.
Як один із варіантів можна взяти VPS із такими характеристиками. Важливі саме ресурси, стабільність диска, наявність резервного копіювання та можливість задати зворотний DNS-запис, а не назва конкретного тарифу.
Коли потрібен dedicated
Виділений сервер потрібен не через сам CrowdSec. Він стає виправданим, якщо на машині працюють бази даних із високим I/O, десятки контейнерів, CI/CD-воркери, ігрові сервери, великий GitLab, власна нода блокчейну або кілька віртуальних машин.
Для CrowdSec слід виділяти щонайменше один vCPU і 512 МБ RAM, але на dedicated зручно зарезервувати 2–4 vCPU і 4–8 ГБ RAM під security stack і системні сервіси. Не розміщуйте єдину копію резервних архівів на тому самому фізичному сервері.
Вплив локації
Локація впливає насамперед на затримку до користувачів і юридичні вимоги до даних. Для CrowdSec відстань до Central API зазвичай не критична: події аналізуються локально. Для web-застосунку обирайте регіон ближче до основної аудиторії, а для адміністративного VPS враховуйте маршрут від вашого робочого місця.
Перевірте, чи надає провайдер PTR-запис, IPv6, фільтрацію вихідного SMTP і можливість відкрити необхідні вхідні порти. Окремо уточніть політику щодо security-сканерів: CrowdSec не повинен використовуватися для активного сканування чужих мереж.
5. Підготовка сервера
Вхід і створення адміністратора
Нижче використовується ім'я deploy. Замініть його на власне. Виконуйте перший вхід під root лише для початкового налаштування, а потім використовуйте sudo. Перед зміною SSH тримайте поточну сесію відкритою та перевіряйте новий вхід у другому терміналі.
# Оновлюємо індекси пакетів
sudo apt update
# Встановлюємо оновлення безпеки та виправлення
sudo apt full-upgrade -y
# Створюємо окремого користувача
sudo adduser deploy
# Дозволяємо йому виконувати адміністративні команди
sudo usermod -aG sudo deploy
# Створюємо каталог для публічних SSH-ключів
sudo install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
З локального комп'ютера додайте публічний ключ. Не копіюйте приватний ключ на сервер.
# Виконується на вашому робочому комп'ютері
ssh-copy-id deploy@SERVER_IP
# Перевіряємо вхід новим користувачем в окремому терміналі
ssh deploy@SERVER_IP
Базові пакети
# Встановлюємо діагностику, шифрування, редактор і керування репозиторіями
sudo apt install -y \
ca-certificates curl gnupg jq git vim htop lsof unzip \
apt-transport-https software-properties-common \
nftables rsyslog logrotate
# Перевіряємо час і синхронізацію годинника
timedatectl status
# Вмикаємо системну синхронізацію часу
sudo timedatectl set-ntp true
SSH hardening
Спочатку переконайтеся, що вхід за ключем працює. Після цього вимкніть парольну автентифікацію та root-вхід. Якщо у вас є автоматизація, яка все ще використовує пароль, вона перестане працювати після застосування файлу.
# Створюємо окремий drop-in для sshd
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 20
X11Forwarding no
AllowUsers deploy
EOF
# Перевіряємо синтаксис перед перезапуском
sudo sshd -t
# Застосовуємо конфігурацію без закриття поточних сесій
sudo systemctl reload ssh
Firewall до встановлення CrowdSec
Відкрийте лише SSH, HTTP і HTTPS. Якщо SSH працює на іншому порту, замініть значення в правилах. Не відкривайте порти баз даних і Docker-сервісів у зовнішній інтернет без потреби.
# Вмикаємо nftables під час завантаження
sudo systemctl enable --now nftables
# Створюємо базовий firewall: loopback, established, SSH і web
sudo tee /etc/nftables.conf >/dev/null <<'EOF'
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state established,related accept
ct state invalid drop
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 accept
tcp dport { 80, 443 } accept
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
EOF
# Завантажуємо правила
sudo nft -f /etc/nftables.conf
# Перевіряємо активний набір правил
sudo nft list ruleset
Чи потрібен fail2ban
У завданні fail2ban встановлюється як базова страховка, але не можна бездумно запускати два незалежні банери з однаковими порогами. Інакше системи можуть блокувати адреси кожна за своїми правилами, а діагностика стане складнішою. Після перевірки CrowdSec зазвичай залишають лише його для SSH і web, а fail2ban вимикають або використовують для окремого застосунку.
# Встановлюємо fail2ban як тимчасовий або резервний механізм
sudo apt install -y fail2ban
# Створюємо безпечний локальний конфіг SSH jail
sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
port = ssh
maxretry = 6
findtime = 10m
bantime = 10m
EOF
# Перезапускаємо fail2ban і переглядаємо стан
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Після введення CrowdSec в експлуатацію можна вимкнути цей jail і залишити fail2ban встановленим для ручного аварійного ввімкнення:
# Вимикаємо дублювальний SSH-jail після успішної перевірки CrowdSec
sudo sed -i 's/^enabled = true/enabled = false/' /etc/fail2ban/jail.d/sshd.local
sudo systemctl restart fail2ban
6. Встановлення CrowdSec, Nginx і Docker
Встановлення CrowdSec
На Debian і Ubuntu використовуйте офіційний репозиторій CrowdSec, а не випадкові PPA. Версія пакета може бути новішою за вказану в статті. У 2026 році орієнтуйтеся на стабільну гілку 1.6.x і перевіряйте пакет перед фіксацією версії.
# Додаємо офіційний signing key CrowdSec
curl -fsSL https://packagecloud.io/crowdsec/crowdsec/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/crowdsec-archive-keyring.gpg
# Додаємо офіційний apt-репозиторій
echo "deb [signed-by=/usr/share/keyrings/crowdsec-archive-keyring.gpg] https://packagecloud.io/crowdsec/crowdsec/debian/ bookworm main" \
| sudo tee /etc/apt/sources.list.d/crowdsec.list
# Оновлюємо індекси та встановлюємо CrowdSec 1.6.x
sudo apt update
sudo apt install -y crowdsec
# Вмикаємо сервіс і перевіряємо встановлену версію
sudo systemctl enable --now crowdsec
sudo cscli version
На Ubuntu 24.04 замініть кодову назву репозиторію на підтримувану офіційним репозиторієм, якщо поточний запис не підходить. Перевірка apt policy crowdsec покаже, звідки взято пакет.
# Показуємо джерело та доступну версію пакета
apt policy crowdsec
# Перевіряємо стан systemd-сервісу
sudo systemctl status crowdsec --no-pager
Встановлення базових колекцій
Колекція — це набір парсерів, сценаріїв і файлів журналів для конкретного сервісу. Не встановлюйте все підряд: зайві сценарії збільшують шум і витрати ресурсів.
# Оновлюємо індекс Hub
sudo cscli hub update
# Встановлюємо сценарії Linux і SSH
sudo cscli collections install crowdsecurity/linux
sudo cscli collections install crowdsecurity/sshd
# Встановлюємо парсери та сценарії Nginx
sudo cscli collections install crowdsecurity/nginx
# Перевіряємо встановлені колекції
sudo cscli collections list
Встановлення firewall-bouncer
Для nftables потрібен пакет firewall-bouncer з backend nftables. Назва пакета може відрізнятися залежно від дистрибутива та репозиторію, тому спочатку знайдіть доступний пакет.
# Шукаємо доступні варіанти bouncer
apt-cache search crowdsec | grep -i bouncer
# Встановлюємо bouncer для nftables
sudo apt install -y crowdsec-firewall-bouncer-nftables
# Вмикаємо застосування рішень на firewall
sudo systemctl enable --now crowdsec-firewall-bouncer
# Перевіряємо стан bouncer
sudo systemctl status crowdsec-firewall-bouncer --no-pager
Встановлення Nginx
Nginx потрібен для зрозумілого access log і проксування застосунків. Якщо reverse proxy уже реалізовано Caddy, Nginx встановлювати не обов'язково; у такому разі підключається колекція для Caddy або журнал застосунку. Для основної схеми залишимо Nginx.
# Встановлюємо Nginx із системного репозиторію
sudo apt install -y nginx
# Запускаємо web-сервер і додаємо його до автозавантаження
sudo systemctl enable --now nginx
# Перевіряємо локальну HTTP-відповідь
curl -I http://127.0.0.1
Встановлення Docker Engine
Для production використовуйте офіційний Docker Engine, а не застарілий пакет docker.io, якщо вам потрібні актуальні Compose plugin і виправлення. Версія 27/28 підходить для типової інсталяції CrowdSec на 2026 рік.
# Додаємо ключ офіційного репозиторію Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Підключаємо репозиторій Docker для Debian 12
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" \
| sudo tee /etc/apt/sources.list.d/docker.list
# Встановлюємо Engine, CLI і Compose plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Дозволяємо deploy працювати з Docker без sudo
sudo usermod -aG docker deploy
# Перевіряємо Docker і Compose
sudo docker version
sudo docker compose version
Після додавання до групи потрібно знову ввійти в SSH. Група docker фактично надає root-права, тому не додавайте до неї випадкових користувачів і не монтуйте Docker socket всередину недовірених контейнерів.
7. Налаштування та перевірка
Підключення журналів SSH і Nginx
У Debian SSH зазвичай записує дані в journald або в /var/log/auth.log. Nginx за замовчуванням використовує /var/log/nginx/access.log і /var/log/nginx/error.log. Перегляньте активну конфігурацію CrowdSec: вона підкаже, які acquisition-файли вже створені пакетом.
# Показываем источники логов CrowdSec
sudo cscli acquisitions list
# Проверяем наличие системных и Nginx-журналов
sudo ls -l /var/log/auth.log /var/log/nginx/access.log /var/log/nginx/error.log
# Читаем последние сообщения CrowdSec
sudo journalctl -u crowdsec -n 100 --no-pager
Якщо acquisition-файл не створено, додайте окрему конфігурацію. Формат може дещо відрізнятися між версіями, тому після зміни завжди перевіряйте синтаксис перезапуском сервісу.
# Создаём источник логов Nginx
sudo tee /etc/crowdsec/acquis.d/nginx.yaml >/dev/null <<'EOF'
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
EOF
# Создаём источник системного auth.log
sudo tee /etc/crowdsec/acquis.d/sshd.yaml >/dev/null <<'EOF'
filenames:
- /var/log/auth.log
labels:
type: syslog
EOF
# Перезапускаем engine после изменения источников
sudo systemctl restart crowdsec
# Проверяем источники ещё раз
sudo cscli acquisitions list
Конфігурація Nginx
Сайт має проксувати застосунок лише через loopback або внутрішню Docker-мережу. Не публікуйте порт застосунку безпосередньо, якщо доступ до нього має здійснюватися через Nginx.
# Создаём виртуальный хост для example.com
sudo tee /etc/nginx/sites-available/example.com >/dev/null <<'EOF'
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log warn;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
}
EOF
# Включаем сайт
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
# Удаляем дефолтный сайт при необходимости
sudo rm -f /etc/nginx/sites-enabled/default
# Проверяем конфигурацию и применяем её
sudo nginx -t
sudo systemctl reload nginx
У production замініть домен на справжній і спрямуйте DNS A-запис на IPv4 VPS. Для IPv6 додайте AAAA-запис лише після перевірки, що firewall і застосунок коректно обробляють IPv6.
HTTPS через Caddy
Якщо ви не хочете вручну обслуговувати сертифікати в Nginx, Caddy може стати єдиним reverse proxy. Не запускайте одночасно Caddy і Nginx на портах 80 і 443. Нижче наведено окремий варіант із Docker Compose: зупиніть Nginx або призначте йому внутрішній порт.
# Создаём каталог Caddy
sudo mkdir -p /opt/caddy/data /opt/caddy/config
sudo chown -R deploy:deploy /opt/caddy
# Переходим в каталог проекта
cd /opt/caddy
# Создаём файл с reverse proxy и автоматическим HTTPS
cat > Caddyfile <<'EOF'
example.com {
encode gzip zstd
reverse_proxy app:8080
header {
X-Content-Type-Options nosniff
X-Frame-Options SAMEORIGIN
Referrer-Policy strict-origin-when-cross-origin
}
}
EOF
# Описываем Caddy и приложение в Compose
cat > compose.yaml <<'EOF'
services:
app:
image: nginx:1.27-alpine
restart: unless-stopped
expose:
- "8080"
caddy:
image: caddy:2.9-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
depends_on:
- app
EOF
# Запускаем стек и проверяем контейнеры
docker compose up -d
docker compose ps
У реальному проєкті замініть тестовий образ застосунку на власний. Caddy самостійно запросить сертифікат, якщо DNS уже вказує на VPS, а вхідні порти 80/443 доступні. Якщо Nginx залишається зовнішнім reverse proxy, Caddy має прослуховувати лише внутрішній порт, а TLS завершується в Nginx.
Збір логів Docker
CrowdSec не повинен читати двійкову базу Docker безпосередньо. Для невеликого сервера простіше налаштувати JSON-файли Docker і спрямувати їх в acquisition. Обмеження розміру логів є обов’язковим, інакше один noisy-контейнер може заповнити диск.
# Ограничиваем размер стандартных Docker-логов
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
EOF
# Перезапускаем Docker; контейнеры могут кратко прерваться
sudo systemctl restart docker
# Проверяем конфигурацию Docker
docker info --format '{{.LoggingDriver}}'
Колекція Docker може аналізувати події через відповідний парсер, але конкретний формат залежить від версії CrowdSec і застосунку. Спочатку встановіть колекцію та перегляньте її acquisition-файли:
# Обновляем Hub и устанавливаем коллекцию Docker
sudo cscli hub update
sudo cscli collections install crowdsecurity/docker
# Просматриваем файлы коллекции
sudo find /etc/crowdsec -type f | grep -i docker
# Перезапускаем CrowdSec после установки коллекции
sudo systemctl restart crowdsec
Реєстрація bouncer і перевірка рішень
Під час встановлення пакет зазвичай автоматично створює API-ключ bouncer. Якщо ключ не створено, згенеруйте його вручну та внесіть до конфігурації bouncer. Не публікуйте цей ключ у Git і не надсилайте його у відкриті issue.
# Смотрим зарегистрированные bouncer
sudo cscli bouncers list
# При необходимости создаём новый ключ
sudo cscli bouncers add firewall-local
# Проверяем локальные решения
sudo cscli decisions list
# Смотрим статистику чтения логов и срабатывания сценариев
sudo cscli metrics
Безпечний тест блокування
Не тестуйте бан зі своєї основної робочої IP-адреси: можна втратити доступ. Використовуйте тимчасову адресу, консоль провайдера або локальне decision із коротким терміном дії. Після тесту видаліть рішення.
# Добавляем тестовый адрес на одну минуту; замените TEST_IP
sudo cscli decisions add --ip TEST_IP --duration 1m --reason "manual-test"
# Проверяем, что решение появилось
sudo cscli decisions list
# Проверяем цепочки CrowdSec в nftables
sudo nft list ruleset | grep -i crowdsec -A 12
# Удаляем тестовое решение
sudo cscli decisions delete --ip TEST_IP
Перевірка SSH і HTTP
# Проверяем открытые TCP-порты на самом сервере
sudo ss -lntup
# Проверяем локальный Nginx
curl -I http://127.0.0.1
# Проверяем HTTPS с внешнего компьютера
curl -I https://example.com
# Проверяем сообщения bouncer
sudo journalctl -u crowdsec-firewall-bouncer -n 100 --no-pager
# Проверяем ошибки Nginx за последние строки
sudo tail -n 50 /var/log/nginx/error.log
Налаштування сповіщень
Для початку достатньо періодично перевіряти метрики та журнали systemd. У production корисно підключити моніторинг: Prometheus node exporter, Uptime Kuma, Zabbix або інший інструмент, який уже використовується. Не надсилайте у сповіщення повні рядки логів, якщо вони можуть містити токени, URL із секретами або персональні дані.
8. Резервні копії та обслуговування
Що необхідно зберігати
/etc/crowdsec/— acquisition, локальні налаштування та сценарії, які ви змінювали./etc/crowdsec/bouncers/— конфігурація firewall-bouncer./etc/ssh/,/etc/nginx/,/etc/nftables.confі конфігурація Caddy.- Compose-файли, шаблони Docker secrets і змінні середовища без розкриття секретів у логах.
- Дані застосунків: бази даних, користувацькі завантаження, сертифікати та persistent volumes.
- Список пакетів і вивід конфігурації, щоб відновити середовище на новому VPS.
Не слід вважати Docker image резервною копією даних. Образ можна завантажити повторно, а вміст volume, базу даних і ключі — ні. Для PostgreSQL створюйте логічний dump, а для MySQL або MariaDB використовуйте відповідний dump-інструмент до копіювання файлів.
Приклад дампа PostgreSQL
# Создаём каталог для локальных временных дампов
sudo install -d -m 700 /var/backups/postgres
# Выполняем сжатый дамп конкретной базы
sudo -u postgres pg_dump -Fc appdb \
> /var/backups/postgres/appdb-$(date +%F).dump
# Удаляем локальные дампы старше семи дней
sudo find /var/backups/postgres -type f -mtime +7 -delete
Restic у зовнішній S3
Резервні копії мають зберігатися поза VPS: у S3-сумісному об’єктному сховищі, на окремому сервері або у двох незалежних місцях. Секрети Restic передавайте через environment file із правами 600. У прикладі використовується S3-сумісне сховище; URL і bucket замініть на власні.
# Устанавливаем restic
sudo apt install -y restic
# Создаём файл секретов с закрытыми правами
sudo tee /root/.restic-env >/dev/null <<'EOF'
export AWS_ACCESS_KEY_ID='CHANGE_ME'
export AWS_SECRET_ACCESS_KEY='CHANGE_ME'
export RESTIC_REPOSITORY='s3:https://s3.example.net/server-backups'
export RESTIC_PASSWORD='CHANGE_ME_LONG_RANDOM_PASSWORD'
EOF
sudo chmod 600 /root/.restic-env
# Инициализируем репозиторий один раз
sudo bash -c 'source /root/.restic-env && restic init'
Не додавайте до архіву каталоги з тимчасовими файлами та Docker-кешем. Секретний файл Restic не можна бекапити в тому самому вигляді разом з архівом: зберігайте пароль у менеджері секретів або в офлайн-копії.
# Создаём скрипт резервного копирования
sudo tee /usr/local/sbin/backup-server.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
source /root/.restic-env
restic backup \
/etc/crowdsec \
/etc/nginx \
/etc/ssh \
/etc/docker \
/etc/nftables.conf \
/opt \
/var/backups/postgres \
--tag "$(hostname)-$(date +%F)"
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
EOF
# Разрешаем запускать скрипт только root
sudo chmod 700 /usr/local/sbin/backup-server.sh
# Выполняем первый backup вручную
sudo /usr/local/sbin/backup-server.sh
# Проверяем список snapshots
sudo bash -c 'source /root/.restic-env && restic snapshots'
Cron і перевірка відновлення
# Запускаем backup ежедневно в 03:15
echo '15 3 * root /usr/local/sbin/backup-server.sh >> /var/log/backup-server.log 2>&1' \
| sudo tee /etc/cron.d/backup-server
# Проверяем структуру cron-файла
sudo chmod 644 /etc/cron.d/backup-server
sudo cat /etc/cron.d/backup-server
# Тестируем восстановление одного файла в отдельный каталог
sudo mkdir -p /tmp/restic-restore
sudo bash -c 'source /root/.restic-env && restic restore latest --target /tmp/restic-restore --include /etc/crowdsec/config.yaml'
Бекап вважається робочим лише після відновлення. Раз на місяць створюйте тимчасовий VPS або окремий каталог і перевіряйте, що конфігурація читається, база імпортується, а Docker Compose запускається з відновленими змінними.
Оновлення
CrowdSec, bouncer і парсери можна оновлювати без зупинки користувацьких застосунків, але зміни firewall завжди потрібно перевіряти. Перед оновленням збережіть поточні рішення та конфігурацію. Для одного VPS краще вибрати коротке maintenance window, особливо якщо оновлюється ядро, Docker або Nginx.
# Сохраняем список установленных пакетов
dpkg-query -W -f='${binary:Package}\t${Version}\n' \
| sudo tee /var/backups/packages-$(date +%F).txt
# Обновляем пакеты
sudo apt update
sudo apt upgrade -y
# Обновляем коллекции CrowdSec из Hub
sudo cscli hub update
sudo cscli hub upgrade
# Проверяем сервисы после обновления
sudo systemctl --failed
sudo systemctl status crowdsec crowdsec-firewall-bouncer nginx --no-pager
Для кількох серверів використовуйте staged rollout: спочатку оновіть один тестовий VPS, перевірте метрики та логи, а потім решту. Rolling update можливий лише за наявності другого reverse proxy або балансувальника. Один сервер без резервного вузла потребує звичайного вікна обслуговування.
9. Усунення несправностей і FAQ
Чому CrowdSec не бачить події SSH?
Перевірте, куди пише sshd: journalctl -u ssh, /var/log/auth.log або інший файл. Потім виконайте sudo cscli acquisitions list і переконайтеся, що джерело має правильний label. Перевірте права на читання та перезапустіть CrowdSec. Якщо використовується journald без файлу, налаштуйте acquisition для systemd відповідно до документації встановленої версії, а не додавайте неіснуючий шлях.
Рішення створюються, але IP не блокуються. Що перевірити?
Спочатку виконайте sudo cscli bouncers list і переконайтеся, що bouncer зареєстрований та має нещодавній останній pull. Потім перевірте systemctl status crowdsec-firewall-bouncer і наявність ланцюжків CrowdSec у nft list ruleset. Частою причиною є встановлений iptables-варіант bouncer у системі на nftables. Встановіть правильний пакет і перевірте backend у конфігурації bouncer.
Яка VPS-конфігурація мінімально підійде?
Для одного SSH і невеликого Nginx технічно вистачить 1 vCPU, 1 ГБ RAM і 20–30 ГБ SSD. Практичний мінімум для Docker і кількох сервісів — 2 vCPU, 4 ГБ RAM і 60 ГБ NVMe. Потрібен публічний IPv4, стабільна мережа та можливість відкрити TCP 22, 80 і 443. Якщо плануються база даних, CI-збірки або важкі контейнери, орієнтуйтеся на 8 ГБ RAM і вище.
Що вибрати — VPS чи dedicated для цього завдання?
Для CrowdSec, SSH, Nginx і кількох контейнерів достатньо VPS. Dedicated виправданий не самим security stack, а високим навантаженням застосунків, великим обсягом RAM, інтенсивним дисковим I/O або вимогою до фізичної ізоляції. Якщо VPS-провайдер надає гарантовані ресурси, окремий диск і резервні копії, він буде простішим і дешевшим в обслуговуванні. Dedicated обирайте за стабільного навантаження, а не «про всяк випадок».
Чому Docker-контейнер доступний з інтернету, хоча порт не дозволений у nftables?
Docker змінює правила forwarding і NAT, тому опублікований порт може обходити очікувану модель фільтрації. Найкраще виправлення — не публікувати порт назовні: використовуйте expose і підключайте контейнер до внутрішньої мережі reverse proxy. Якщо публікація обов'язкова, додайте явні правила в ланцюжки Docker або використовуйте окрему архітектуру firewall, попередньо перевіривши її на тестовому сервері.
Як прибрати помилкове блокування свого IP?
Перегляньте рішення командою sudo cscli decisions list. Видаліть конкретну адресу через sudo cscli decisions delete --ip YOUR_IP. Якщо адреса знову з'являється, знайдіть джерело в метриках і логах. Причиною може бути неправильний reverse proxy: CrowdSec бачить IP балансувальника замість клієнта, або ваш моніторинг генерує надто багато запитів. Налаштуйте trusted proxies лише для відомих адрес і не довіряйте довільному заголовку X-Forwarded-For.
Чи можна залишити fail2ban і CrowdSec одночасно?
Технічно можна, але однакові SSH-jails створюють дублювання та ускладнюють розслідування. Для простої схеми залиште CrowdSec єдиним джерелом блокувань, а fail2ban вимкніть. Одночасна робота виправдана, якщо fail2ban захищає окремий сервіс, для якого немає відповідного CrowdSec-парсера. У такому разі розділіть jails, терміни блокування та ланцюжки firewall, потім задокументуйте, який компонент відповідає за кожен тип подій.
HTTPS не видається Caddy. Що перевірити?
Переконайтеся, що DNS A і AAAA вказують на правильний сервер, а порти 80 і 443 доступні ззовні. Якщо AAAA існує, але IPv6 не налаштований, ACME-клієнт може звертатися до неправильної адреси: тимчасово виправте IPv6 або налаштуйте його коректно. Перевірте логи docker compose logs caddy, переконайтеся, що інший процес не зайняв порти, і не запускайте одночасно зовнішній Nginx і Caddy на одному socket.
Диск швидко заповнюється логами. Як виправити?
Перевірте розмір каталогів командами sudo du -xhd1 /var/log /var/lib/docker. Налаштуйте logrotate для Nginx, ліміти Docker max-size і max-file, а також retention для journald. Не видаляйте активні логи вручну: після ротації надішліть сервісу reload. Потім перевірте, що CrowdSec читає новий файл і не втратив позицію після ротації.
10. Висновки та наступні кроки
На VPS тепер працюють CrowdSec engine, сценарії для SSH і Nginx, firewall-bouncer на nftables та контрольовані Docker-сервіси. Вхід через SSH обмежений ключами, web-трафік проходить через reverse proxy, а конфігурації та дані підготовлені до резервного копіювання.
Наступний крок — підключити моніторинг метрик і регулярно проводити тест відновлення. У разі зростання навантаження винесіть бази даних і застосунки на окремі вузли, а за кількох VPS використовуйте централізовані логи та єдиний процес оновлення.
- Перевірте false positive на реальному трафіку та додайте винятки лише для довірених мереж.
- Налаштуйте staged updates, зовнішній backup і щомісячний disaster recovery test.
- Для кількох доменів або серверів додайте зовнішній WAF/CDN, не замінюючи ним локальний захист CrowdSec.