Это старая версия документа!
## Управление
### Проверка статуса ```bash fail2ban-client status fail2ban-client status nginx-scan-block ```
### Разбан IP ```bash fail2ban-client unban 1.2.3.4 fail2ban-client set nginx-scan-block unbanip 1.2.3.4 ```
### Ручной бан ```bash fail2ban-client set nginx-scan-block banip 1.2.3.4 ```
### Перезапуск ```bash systemctl restart fail2ban ```
### Просмотр логов ```bash tail -f /var/log/fail2ban.log tail -f /opt/fail2ban/logs/parser.log ```
## Настройка параметров
Редактировать файл: `/opt/fail2ban/config/jail.d/nginx-protection.conf`
- `maxretry` - количество попыток до бана - `findtime` - временное окно поиска (секунды) - `bantime` - время бана (секунды) - `ignoreip` - игнорируемые IP
После изменений: ```bash systemctl restart fail2ban ```
## Мониторинг
### Просмотр забаненных IP ```bash iptables -L f2b-nginx-scan -n -v iptables -L f2b-nginx-404 -n -v iptables -L f2b-nginx-dos -n -v ```
### Статистика ```bash for jail in nginx-scan-block nginx-404-flood nginx-dos-block; do
echo "=== $jail ===" fail2ban-client status $jail echo ""
done ``` README_EOF
log_info «Создан README файл: ${FAIL2BAN_BASE}/README.md» echo «»
log_info «Установка завершена! Ваш сервер защищен 🛡️» </code>
Шаг 3: Настройка параметров (опционально)
Перед запуском вы можете изменить следующие параметры в начале скрипта:
NPM_LOG_DIR- путь к логам Nginx Proxy ManagerNPM_CONTAINER_NAME- имя контейнера NPMIGNORE_IP- список игнорируемых IP адресов
Шаг 4: Запуск скрипта
chmod +x install-fail2ban.sh ./install-fail2ban.sh
Скрипт автоматически выполнит все необходимые действия:
- Проверит наличие Nginx Proxy Manager
- Установит Fail2ban
- Создаст структуру каталогов
- Создаст и настроит парсер логов
- Создаст все фильтры
- Настроит jail конфигурацию
- Протестирует конфигурацию
- Добавит парсер в cron
- Запустит Fail2ban
- Выведет статистику работы
Результат автоматической установки
После успешного выполнения скрипта вы увидите:
========================================== Установка и настройка завершена успешно! ========================================== Создано: - Скрипт парсера: /opt/fail2ban/scripts/parse-nginx-logs.sh - Лог-файл: /opt/fail2ban/logs/nginx-access.log - Фильтры: /opt/fail2ban/config/filter.d/ - Конфигурация jail: /opt/fail2ban/config/jail.d/nginx-protection.conf Активные защиты: ✅ nginx-scan-block - Блокировка сканирования (maxretry: 3, bantime: 2 часа) ✅ nginx-404-flood - Блокировка 404 флуда (maxretry: 10, bantime: 1 час) ✅ nginx-dos-block - Блокировка DoS (maxretry: 50/мин, bantime: 10 минут) ✅ sshd - Защита SSH
Ручная установка (пошаговая)
Если вы предпочитаете ручную установку с полным контролем каждого шага, следуйте инструкциям ниже.
Установка Fail2ban
apt update apt install fail2ban -y
Создание структуры каталогов
mkdir -p /opt/fail2ban/{scripts,logs,config/{jail.d,filter.d}}
Создание парсера логов Nginx Proxy Manager
Создайте файл /opt/fail2ban/scripts/parse-nginx-logs.sh:
cat > /opt/fail2ban/scripts/parse-nginx-logs.sh << 'EOF' #!/bin/bash # Скрипт парсинга логов nginx-proxy-manager для fail2ban # Обрабатывает все access логи из папки nginxpm LOG_DIR="/opt/nginxpm/data/logs" LOG_FILE="/opt/fail2ban/logs/nginx-access.log" CONTAINER_NAME="nginxpm" PARSER_LOG="/opt/fail2ban/logs/parser.log" # Создаем директории если они не существуют mkdir -p "$(dirname "$LOG_FILE")" "$(dirname "$PARSER_LOG")" # Проверяем, что контейнер запущен if ! docker ps --format "table {{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then echo "$(date): Контейнер $CONTAINER_NAME не найден или не запущен" >> "$PARSER_LOG" exit 1 fi # Проверяем существование директории с логами if [ ! -d "$LOG_DIR" ]; then echo "$(date): Директория логов $LOG_DIR не найдена" >> "$PARSER_LOG" exit 1 fi # Очищаем целевой файл > "$LOG_FILE" # Счетчик обработанных файлов и строк processed_files=0 total_lines=0 # Обрабатываем все файлы с окончанием *_access.log for logfile in "$LOG_DIR"/proxy-host-*_access.log; do # Проверяем, что файл существует (на случай если паттерн не найден) if [ -f "$logfile" ]; then lines_from_file=$(tail -n 2000 "$logfile" | wc -l) tail -n 2000 "$logfile" >> "$LOG_FILE" processed_files=$((processed_files + 1)) total_lines=$((total_lines + lines_from_file)) echo "$(date): Обработан файл: $(basename "$logfile") - $lines_from_file строк" >> "$PARSER_LOG" fi done # Если не найдено ни одного файла логов if [ $processed_files -eq 0 ]; then echo "$(date): Не найдено файлов логов *_access.log в директории $LOG_DIR" >> "$PARSER_LOG" # Создаем пустой файл чтобы fail2ban не ругался touch "$LOG_FILE" fi # Устанавливаем права доступа chmod 644 "$LOG_FILE" # Логируем статистику каждый час (когда минуты = 00) MINUTE=$(date +%M) if [ "$MINUTE" = "00" ]; then final_lines=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0") echo "$(date): Итого обработано $processed_files файлов, $final_lines записей из контейнера $CONTAINER_NAME" >> "$PARSER_LOG" fi # Ротация логов parser.log (если больше 5MB) if [ -f "$PARSER_LOG" ] && [ $(stat -c%s "$PARSER_LOG" 2>/dev/null || echo 0) -gt 5242880 ]; then mv "$PARSER_LOG" "$PARSER_LOG.old" touch "$PARSER_LOG" chmod 644 "$PARSER_LOG" fi # Удаление записей старше 30 дней из лог-файла if [ -f "$LOG_FILE" ] && [ -s "$LOG_FILE" ]; then CUTOFF_DATE=$(date -d '30 days ago' '+%d/%b/%Y') TEMP_FILTERED="/tmp/nginx-filtered-logs" # Фильтруем записи не старше 30 дней awk -v cutoff="$CUTOFF_DATE" ' { # Извлекаем дату из строки лога (формат: DD/MMM/YYYY) match($0, /\[([0-9]{2}\/[A-Za-z]{3}\/[0-9]{4})/, date_match) if (date_match[1]) { # Преобразуем дату в timestamp для сравнения cmd = "date -d \"" date_match[1] "\" +%s 2>/dev/null" cmd | getline log_timestamp close(cmd) cmd2 = "date -d \"" cutoff "\" +%s 2>/dev/null" cmd2 | getline cutoff_timestamp close(cmd2) # Если дата лога >= даты отсечки, выводим строку if (log_timestamp >= cutoff_timestamp) { print $0 } } else { # Если не удалось извлечь дату, оставляем запись print $0 } }' "$LOG_FILE" > "$TEMP_FILTERED" # Заменяем оригинальный файл отфильтрованным if [ -f "$TEMP_FILTERED" ]; then mv "$TEMP_FILTERED" "$LOG_FILE" chmod 644 "$LOG_FILE" fi fi # Ротация основного лог-файла (если больше 10MB) if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt 10485760 ]; then mv "$LOG_FILE" "$LOG_FILE.old" touch "$LOG_FILE" chmod 644 "$LOG_FILE" echo "$(date): Выполнена ротация лог-файла $LOG_FILE" >> "$PARSER_LOG" fi exit 0 EOF
Установка прав на скрипт:
chmod +x /opt/fail2ban/scripts/parse-nginx-logs.sh
Первый запуск парсера:
/opt/fail2ban/scripts/parse-nginx-logs.sh ls -lh /opt/fail2ban/logs/nginx-access.log tail -10 /opt/fail2ban/logs/nginx-access.log
Добавление скрипта в cron:
(crontab -l 2>/dev/null; echo "*/2 * * * * /opt/fail2ban/scripts/parse-nginx-logs.sh") | crontab -
Проверка добавления в cron:
crontab -l
Настройка фильтров Fail2ban
Создание фильтра для блокировки сканирования:
cat > /opt/fail2ban/config/filter.d/nginx-scan-block.conf << 'EOF' [Definition] # Формат NPM: [DATE] - STATUS STATUS - METHOD PROTOCOL DOMAIN "PATH" [Client IP] failregex = ^\[.*\] - \d+ \d+ - GET https? .* ".*(/\.env|/\.git|/\.aws|/\.ssh|/config|/backup|wp-config|phpinfo|admin/config|server-status|server-info).*" \[Client <HOST>\] ^\[.*\] - 40\d \d+ - GET https? .* ".*\.(php|asp|jsp|cgi|pl|py).*" \[Client <HOST>\] ^\[.*\] - \d+ \d+ - GET https? .* ".*\.\.\/.*" \[Client <HOST>\] ^\[.*\] - \d+ \d+ - GET https? .* ".*(union|select|insert|update|delete|drop|create|alter).*" \[Client <HOST>\] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(<script|javascript:|vbscript:|onload|onerror).*" \[Client <HOST>\] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(\||`|;|<|>|\\|\{|\}|\[|\]).*" \[Client <HOST>\] ^\[.*\] - \d+ \d+ - GET https? .* ".*/(etc/|var/|bin/|usr/bin/|tmp/|proc/).*" \[Client <HOST>\] ignoreregex = EOF
Создание фильтра для блокировки 404 флуда:
cat > /opt/fail2ban/config/filter.d/nginx-404-flood.conf << 'EOF' [Definition] # Блокировка множественных 404 ошибок failregex = ^\[.*\] - 404 \d+ - (GET|POST|HEAD) https? .* ".*" \[Client <HOST>\] ignoreregex = EOF
Создание фильтра для блокировки DoS:
cat > /opt/fail2ban/config/filter.d/nginx-dos-block.conf << 'EOF' [Definition] # Блокировка слишком частых запросов (DoS) failregex = ^\[.*\] - \d+ \d+ - (GET|POST|HEAD) https? .* ".*" \[Client <HOST>\] ignoreregex = ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*\.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg).*" \[Client <HOST>\] EOF
Создание символических ссылок на фильтры:
ln -sf /opt/fail2ban/config/filter.d/nginx-scan-block.conf /etc/fail2ban/filter.d/nginx-scan-block.conf ln -sf /opt/fail2ban/config/filter.d/nginx-404-flood.conf /etc/fail2ban/filter.d/nginx-404-flood.conf ln -sf /opt/fail2ban/config/filter.d/nginx-dos-block.conf /etc/fail2ban/filter.d/nginx-dos-block.conf
Настройка jail для Nginx Proxy Manager
ВАЖНО: Замените IP адреса в параметре ignoreip на свои локальные сети и доверенные IP.
cat > /opt/fail2ban/config/jail.d/nginx-protection.conf << 'EOF' # Jail конфигурация для nginx защиты [DEFAULT] # Время бана в секундах (1 час = 3600) bantime = 3600 # Время поиска нарушений (5 минут = 300) findtime = 300 # Игнорировать локальные IP ignoreip = 127.0.0.1/8 ::1 192.168.0.0/24 172.16.0.0/12 10.0.0.0/8 [nginx-scan-block] enabled = true port = http,https filter = nginx-scan-block logpath = /opt/fail2ban/logs/nginx-access.log backend = polling maxretry = 3 bantime = 7200 findtime = 300 action = iptables-multiport[name=nginx-scan, port="http,https", protocol=tcp] [nginx-dos-block] enabled = true port = http,https filter = nginx-dos-block logpath = /opt/fail2ban/logs/nginx-access.log backend = polling maxretry = 50 bantime = 600 findtime = 60 action = iptables-multiport[name=nginx-dos, port="http,https", protocol=tcp] [nginx-404-flood] enabled = true port = http,https filter = nginx-404-flood logpath = /opt/fail2ban/logs/nginx-access.log backend = polling maxretry = 10 bantime = 3600 findtime = 600 action = iptables-multiport[name=nginx-404, port="http,https", protocol=tcp] EOF
Создание символической ссылки на jail:
ln -sf /opt/fail2ban/config/jail.d/nginx-protection.conf /etc/fail2ban/jail.d/nginx-protection.conf
Тестирование конфигурации
Проверка синтаксиса конфигурации:
fail2ban-client -t
Ожидаемый результат:
OK: configuration test is successful
Тестирование фильтров на реальных логах:
fail2ban-regex /opt/fail2ban/logs/nginx-access.log /opt/fail2ban/config/filter.d/nginx-scan-block.conf fail2ban-regex /opt/fail2ban/logs/nginx-access.log /opt/fail2ban/config/filter.d/nginx-404-flood.conf fail2ban-regex /opt/fail2ban/logs/nginx-access.log /opt/fail2ban/config/filter.d/nginx-dos-block.conf
Должны быть найдены совпадения (matched > 0).
Запуск и включение автозагрузки
# Включить автозагрузку systemctl enable fail2ban # Запустить службу systemctl start fail2ban # Проверить статус systemctl status fail2ban
Проверка работы
Проверка активных jail
fail2ban-client status
Ожидаемый вывод:
Status |- Number of jail: 4 `- Jail list: nginx-404-flood, nginx-dos-block, nginx-scan-block, sshd
Проверка статуса конкретного jail
fail2ban-client status nginx-scan-block
fail2ban-client status nginx-404-flood
fail2ban-client status nginx-dos-block
Пример вывода:
Status for the jail: nginx-scan-block |- Filter | |- Currently failed: 5 | |- Total failed: 176 | `- File list: /opt/fail2ban/logs/nginx-access.log `- Actions |- Currently banned: 2 |- Total banned: 2 `- Banned IP list: 3.96.220.169 56.228.32.138
Проверка правил iptables
iptables -L -n | grep -E "Chain|nginx"
Ожидаемый результат:
Chain INPUT (policy ACCEPT) f2b-nginx-dos 6 -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 f2b-nginx-404 6 -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 f2b-nginx-scan 6 -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 Chain f2b-nginx-404 (1 references) Chain f2b-nginx-dos (1 references) Chain f2b-nginx-scan (1 references)
Детальный просмотр забаненных IP:
iptables -L f2b-nginx-scan -n -v iptables -L f2b-nginx-404 -n -v iptables -L f2b-nginx-dos -n -v
Мониторинг
Просмотр логов Fail2ban
# Последние 50 строк tail -50 /var/log/fail2ban.log # Только баны tail -100 /var/log/fail2ban.log | grep -E "Ban|Unban" # Мониторинг в реальном времени tail -f /var/log/fail2ban.log
Просмотр логов парсера
tail -50 /opt/fail2ban/logs/parser.log
Общая статистика
echo "=== NGINX SCAN BLOCK ===" fail2ban-client status nginx-scan-block echo "" echo "=== NGINX 404 FLOOD ===" fail2ban-client status nginx-404-flood echo "" echo "=== NGINX DOS BLOCK ===" fail2ban-client status nginx-dos-block
Управление банами
Разбан IP адреса
# Разбан в конкретном jail fail2ban-client set nginx-scan-block unbanip 1.2.3.4 # Разбан во всех jail fail2ban-client unban 1.2.3.4
Ручной бан IP адреса
fail2ban-client set nginx-scan-block banip 1.2.3.4
Настройка параметров защиты
Описание параметров jail
| Параметр | Описание | Рекомендуемое значение |
|---|---|---|
maxretry | Количество попыток до бана | 3-10 для scan, 50 для DoS, 10 для 404 |
findtime | Временное окно поиска нарушений (секунды) | 300 (5 минут) |
bantime | Время бана (секунды) | 3600-7200 (1-2 часа) |
nginx-scan-block (сканирование)
- maxretry: 3 попытки
- findtime: 300 секунд (5 минут)
- bantime: 7200 секунд (2 часа)
Блокирует попытки доступа к:
- Конфигурационным файлам (.env, .git, wp-config.php)
- Скриптам (.php, .asp, .jsp, .cgi)
- SQL инъекциям
- XSS атакам
- Path traversal
nginx-404-flood (404 флуд)
- maxretry: 10 попыток
- findtime: 600 секунд (10 минут)
- bantime: 3600 секунд (1 час)
Блокирует множественные запросы к несуществующим страницам.
nginx-dos-block (DoS атаки)
- maxretry: 50 запросов
- findtime: 60 секунд (1 минута)
- bantime: 600 секунд (10 минут)
Блокирует слишком частые запросы, игнорируя статические файлы (css, js, изображения).
Troubleshooting
Fail2ban не запускается
Проверка логов:
journalctl -xeu fail2ban
systemctl status fail2ban
Проверка конфигурации:
fail2ban-client -d
Jail не банит атаки
Проверка чтения лог-файла:
fail2ban-client status nginx-scan-block
Должно быть File list: /opt/fail2ban/logs/nginx-access.log, а не Journal matches.
Если видите Journal matches, убедитесь что в конфигурации jail указан backend = polling.
Фильтры не находят совпадений
Тестирование фильтра:
fail2ban-regex /opt/fail2ban/logs/nginx-access.log /opt/fail2ban/config/filter.d/nginx-scan-block.conf --print-all-matched
Проверка формата логов:
head -3 /opt/fail2ban/logs/nginx-access.log
Формат должен быть:
[DATE] - STATUS STATUS - METHOD PROTOCOL DOMAIN "PATH" [Client IP] ...
Парсер не создает лог-файл
Проверка работы парсера:
bash -x /opt/fail2ban/scripts/parse-nginx-logs.sh cat /opt/fail2ban/logs/parser.log
Проверка наличия логов Nginx Proxy Manager:
ls -la /opt/nginxpm/data/logs/proxy-host-*_access.log
Проверка работы контейнера:
docker ps | grep nginxpm
Автоматическое обновление
Fail2ban обновляется вместе с системой:
apt update
apt upgrade fail2ban -y
systemctl restart fail2ban
Резервное копирование
Файлы для бэкапа
# Конфигурация /opt/fail2ban/config/ # Скрипты /opt/fail2ban/scripts/ # Логи (опционально) /opt/fail2ban/logs/
Создание бэкапа
tar -czf fail2ban-backup-$(date +%Y%m%d).tar.gz \ /opt/fail2ban/config/ \ /opt/fail2ban/scripts/ \ /etc/fail2ban/jail.d/nginx-protection.conf \ /etc/fail2ban/filter.d/nginx-*.conf
Удаление
# Остановить службу systemctl stop fail2ban systemctl disable fail2ban # Удалить пакет apt remove --purge fail2ban -y # Удалить конфигурацию rm -rf /opt/fail2ban rm -f /etc/fail2ban/jail.d/nginx-protection.conf rm -f /etc/fail2ban/filter.d/nginx-scan-block.conf rm -f /etc/fail2ban/filter.d/nginx-404-flood.conf rm -f /etc/fail2ban/filter.d/nginx-dos-block.conf # Удалить из cron crontab -e # Удалить строку с parse-nginx-logs.sh # Очистить правила iptables iptables -F
Заключение
После выполнения всех шагов ваш сервер будет защищен от:
- ✅ Сканирования уязвимостей
- ✅ 404 флуда
- ✅ DoS атак
- ✅ SSH брутфорса
Fail2ban автоматически:
- Собирает логи из Nginx Proxy Manager каждые 2 минуты
- Анализирует запросы на предмет атак
- Блокирует подозрительные IP на уровне iptables
- Автоматически разбанивает IP после истечения времени бана
Полезные ссылки
Автор: Nick
Дата создания: 2025-11-30
Последнее обновление: 2025-11-30