====== Установка и настройка Fail2ban для Nginx Proxy Manager ====== ===== Описание ===== Данная инструкция описывает процесс установки и настройки Fail2ban для защиты Nginx Proxy Manager от: * Сканирования уязвимостей * 404 флуда * DoS атак * SSH брутфорса ===== Требования ===== * Ubuntu Server 24.04 (или аналогичный дистрибутив) * Nginx Proxy Manager установленный в Docker * Root доступ к серверу ===== Быстрая установка (автоматический скрипт) ===== **Рекомендуется:** Используйте автоматический скрипт установки для быстрой настройки всей системы за один шаг. ==== Шаг 1: Создание скрипта установки ==== nano install-fail2ban.sh ==== Шаг 2: Содержимое скрипта ==== Скопируйте следующий код в файл: #!/bin/bash ################################################################################ # Скрипт автоматической установки и настройки Fail2ban для Nginx Proxy Manager # Версия: 1.0 # Дата: 2025-11-30 ################################################################################ set -e # Остановка при ошибке # Цвета для вывода RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Функция вывода сообщений log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # Проверка прав root if [[ $EUID -ne 0 ]]; then log_error "Этот скрипт должен быть запущен с правами root" exit 1 fi log_info "Начало установки и настройки Fail2ban для Nginx Proxy Manager" echo "" ################################################################################ # НАСТРОЙКИ - ИЗМЕНИТЕ ПОД СВОИ НУЖДЫ ################################################################################ # Путь к логам Nginx Proxy Manager NPM_LOG_DIR="/opt/nginxpm/data/logs" # Имя контейнера Nginx Proxy Manager NPM_CONTAINER_NAME="nginxpm" # Директории Fail2ban FAIL2BAN_BASE="/opt/fail2ban" FAIL2BAN_SCRIPTS="${FAIL2BAN_BASE}/scripts" FAIL2BAN_LOGS="${FAIL2BAN_BASE}/logs" FAIL2BAN_CONFIG="${FAIL2BAN_BASE}/config" FAIL2BAN_JAIL_D="${FAIL2BAN_CONFIG}/jail.d" FAIL2BAN_FILTER_D="${FAIL2BAN_CONFIG}/filter.d" # Файл лога для fail2ban NGINX_ACCESS_LOG="${FAIL2BAN_LOGS}/nginx-access.log" # Игнорируемые IP (локальные сети) IGNORE_IP="127.0.0.1/8 ::1 192.168.0.0/24 172.16.0.0/12 10.0.0.0/8" ################################################################################ # Шаг 1: Проверка существования Nginx Proxy Manager ################################################################################ log_info "Проверка наличия контейнера Nginx Proxy Manager..." if ! docker ps --format "{{.Names}}" | grep -q "^${NPM_CONTAINER_NAME}$"; then log_error "Контейнер ${NPM_CONTAINER_NAME} не найден или не запущен" log_error "Убедитесь что Nginx Proxy Manager установлен и запущен" exit 1 fi if [ ! -d "$NPM_LOG_DIR" ]; then log_error "Директория логов ${NPM_LOG_DIR} не найдена" exit 1 fi log_info "Контейнер ${NPM_CONTAINER_NAME} найден и работает" echo "" ################################################################################ # Шаг 2: Установка Fail2ban ################################################################################ log_info "Установка Fail2ban..." apt update -qq apt install -y fail2ban >/dev/null 2>&1 log_info "Fail2ban успешно установлен" echo "" ################################################################################ # Шаг 3: Создание структуры каталогов ################################################################################ log_info "Создание структуры каталогов..." mkdir -p "${FAIL2BAN_SCRIPTS}" mkdir -p "${FAIL2BAN_LOGS}" mkdir -p "${FAIL2BAN_JAIL_D}" mkdir -p "${FAIL2BAN_FILTER_D}" log_info "Структура каталогов создана" echo "" ################################################################################ # Шаг 4: Создание скрипта парсера логов ################################################################################ log_info "Создание скрипта парсера логов..." cat > "${FAIL2BAN_SCRIPTS}/parse-nginx-logs.sh" << 'PARSER_EOF' #!/bin/bash # Скрипт парсинга логов nginx-proxy-manager для fail2ban 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 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): Файлы логов не найдены" >> "$PARSER_LOG" touch "$LOG_FILE" fi chmod 644 "$LOG_FILE" MINUTE=$(date +%M) if [ "$MINUTE" = "00" ]; then final_lines=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0") echo "$(date): Обработано $processed_files файлов, $final_lines записей" >> "$PARSER_LOG" fi 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 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): Ротация лог-файла" >> "$PARSER_LOG" fi exit 0 PARSER_EOF chmod +x "${FAIL2BAN_SCRIPTS}/parse-nginx-logs.sh" log_info "Скрипт парсера создан" echo "" ################################################################################ # Шаг 5: Первый запуск парсера ################################################################################ log_info "Первый запуск парсера..." "${FAIL2BAN_SCRIPTS}/parse-nginx-logs.sh" if [ -f "$NGINX_ACCESS_LOG" ]; then log_info "Лог-файл создан: ${NGINX_ACCESS_LOG}" log_info "Количество строк: $(wc -l < ${NGINX_ACCESS_LOG})" else log_error "Не удалось создать лог-файл" exit 1 fi echo "" ################################################################################ # Шаг 6: Создание фильтров Fail2ban ################################################################################ log_info "Создание фильтров Fail2ban..." cat > "${FAIL2BAN_FILTER_D}/nginx-scan-block.conf" << 'FILTER_SCAN_EOF' [Definition] failregex = ^\[.*\] - \d+ \d+ - GET https? .* ".*(/\.env|/\.git|/\.aws|/\.ssh|/config|/backup|wp-config|phpinfo|admin/config|server-status|server-info).*" \[Client \] ^\[.*\] - 40\d \d+ - GET https? .* ".*\.(php|asp|jsp|cgi|pl|py).*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*\.\.\/.*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*(union|select|insert|update|delete|drop|create|alter).*" \[Client \] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(\] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(\||`|;|<|>|\\|\{|\}|\[|\]).*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*/(etc/|var/|bin/|usr/bin/|tmp/|proc/).*" \[Client \] ignoreregex = FILTER_SCAN_EOF cat > "${FAIL2BAN_FILTER_D}/nginx-404-flood.conf" << 'FILTER_404_EOF' [Definition] failregex = ^\[.*\] - 404 \d+ - (GET|POST|HEAD) https? .* ".*" \[Client \] ignoreregex = FILTER_404_EOF cat > "${FAIL2BAN_FILTER_D}/nginx-dos-block.conf" << 'FILTER_DOS_EOF' [Definition] failregex = ^\[.*\] - \d+ \d+ - (GET|POST|HEAD) https? .* ".*" \[Client \] ignoreregex = ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*\.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg).*" \[Client \] FILTER_DOS_EOF ln -sf "${FAIL2BAN_FILTER_D}/nginx-scan-block.conf" /etc/fail2ban/filter.d/nginx-scan-block.conf ln -sf "${FAIL2BAN_FILTER_D}/nginx-404-flood.conf" /etc/fail2ban/filter.d/nginx-404-flood.conf ln -sf "${FAIL2BAN_FILTER_D}/nginx-dos-block.conf" /etc/fail2ban/filter.d/nginx-dos-block.conf log_info "Фильтры созданы" echo "" ################################################################################ # Шаг 7: Создание конфигурации jail ################################################################################ log_info "Создание конфигурации jail..." cat > "${FAIL2BAN_JAIL_D}/nginx-protection.conf" << JAIL_EOF [DEFAULT] bantime = 3600 findtime = 300 ignoreip = ${IGNORE_IP} [nginx-scan-block] enabled = true port = http,https filter = nginx-scan-block logpath = ${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 = ${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 = ${NGINX_ACCESS_LOG} backend = polling maxretry = 10 bantime = 3600 findtime = 600 action = iptables-multiport[name=nginx-404, port="http,https", protocol=tcp] JAIL_EOF ln -sf "${FAIL2BAN_JAIL_D}/nginx-protection.conf" /etc/fail2ban/jail.d/nginx-protection.conf log_info "Конфигурация jail создана" echo "" ################################################################################ # Шаг 8: Тестирование ################################################################################ log_info "Тестирование конфигурации..." if fail2ban-client -t; then log_info "Конфигурация корректна" else log_error "Ошибка в конфигурации" exit 1 fi echo "" log_info "Тестирование фильтров..." fail2ban-regex "${NGINX_ACCESS_LOG}" "${FAIL2BAN_FILTER_D}/nginx-scan-block.conf" | grep -E "Failregex:|matched" fail2ban-regex "${NGINX_ACCESS_LOG}" "${FAIL2BAN_FILTER_D}/nginx-404-flood.conf" | grep -E "Failregex:|matched" fail2ban-regex "${NGINX_ACCESS_LOG}" "${FAIL2BAN_FILTER_D}/nginx-dos-block.conf" | grep -E "Failregex:|matched" echo "" ################################################################################ # Шаг 9: Добавление в cron ################################################################################ log_info "Добавление в cron..." CRON_ENTRY="*/2 * * * * ${FAIL2BAN_SCRIPTS}/parse-nginx-logs.sh" if crontab -l 2>/dev/null | grep -q "parse-nginx-logs.sh"; then log_warn "Уже добавлено в cron" else (crontab -l 2>/dev/null; echo "$CRON_ENTRY") | crontab - log_info "Добавлено в cron" fi echo "" ################################################################################ # Шаг 10: Запуск ################################################################################ log_info "Запуск Fail2ban..." systemctl enable fail2ban >/dev/null 2>&1 systemctl restart fail2ban sleep 5 if systemctl is-active --quiet fail2ban; then log_info "Fail2ban успешно запущен" else log_error "Не удалось запустить Fail2ban" exit 1 fi echo "" ################################################################################ # Проверка ################################################################################ log_info "Проверка jail..." echo "" fail2ban-client status echo "" fail2ban-client status nginx-scan-block echo "" fail2ban-client status nginx-404-flood echo "" fail2ban-client status nginx-dos-block echo "" ################################################################################ # Завершение ################################################################################ log_info "==========================================" log_info "Установка завершена успешно!" log_info "==========================================" echo "" echo "Создано:" echo " - Парсер: ${FAIL2BAN_SCRIPTS}/parse-nginx-logs.sh" echo " - Логи: ${NGINX_ACCESS_LOG}" echo " - Фильтры: ${FAIL2BAN_FILTER_D}/" echo " - Jail: ${FAIL2BAN_JAIL_D}/nginx-protection.conf" echo "" echo "Защита:" echo " ✅ nginx-scan-block (3 попытки, бан 2 часа)" echo " ✅ nginx-404-flood (10 попыток, бан 1 час)" echo " ✅ nginx-dos-block (50/мин, бан 10 минут)" echo " ✅ sshd" echo "" echo "Команды:" echo " fail2ban-client status" echo " fail2ban-client status nginx-scan-block" echo " iptables -L f2b-nginx-scan -n -v" echo " tail -f /var/log/fail2ban.log" echo " fail2ban-client unban IP" echo "" cat > "${FAIL2BAN_BASE}/README.md" << 'README_EOF' # Fail2ban для Nginx Proxy Manager ## Управление ### Проверка статуса ```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 - исключения После изменений: ```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 "Установка завершена! Сервер защищен 🛡️" ==== Шаг 3: Настройка параметров (опционально) ==== Перед запуском вы можете изменить следующие параметры в начале скрипта: * ''NPM_LOG_DIR'' - путь к логам Nginx Proxy Manager * ''NPM_CONTAINER_NAME'' - имя контейнера NPM * ''IGNORE_IP'' - список игнорируемых IP адресов ==== Шаг 4: Запуск скрипта ==== chmod +x install-fail2ban.sh ./install-fail2ban.sh Скрипт автоматически выполнит все необходимые действия: - Проверит наличие Nginx Proxy Manager - Установит Fail2ban - Создаст структуру каталогов - Создаст и настроит парсер логов - Создаст все фильтры - Настроит jail конфигурацию - Протестирует конфигурацию - Добавит парсер в cron - Запустит Fail2ban - Выведет статистику работы ==== Результат автоматической установки ==== После успешного выполнения скрипта вы увидите: ========================================== Установка и настройка завершена успешно! ========================================== Защита: ✅ nginx-scan-block (3 попытки, бан 2 часа) ✅ nginx-404-flood (10 попыток, бан 1 час) ✅ nginx-dos-block (50/мин, бан 10 минут) ✅ sshd ===== Ручная установка (пошаговая) ===== Если вы предпочитаете ручную установку с полным контролем каждого шага, следуйте инструкциям ниже. ==== Установка Fail2ban ==== apt update apt install fail2ban -y ==== Создание структуры каталогов ==== mkdir -p /opt/fail2ban/{scripts,logs,config/{jail.d,filter.d}} ==== Создание парсера логов ==== nano /opt/fail2ban/scripts/parse-nginx-logs.sh Содержимое файла указано в автоматическом скрипте выше (раздел PARSER_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 Добавление в cron: (crontab -l 2>/dev/null; echo "*/2 * * * * /opt/fail2ban/scripts/parse-nginx-logs.sh") | crontab - crontab -l ==== Создание фильтров ==== # Фильтр сканирования cat > /opt/fail2ban/config/filter.d/nginx-scan-block.conf << 'EOF' [Definition] failregex = ^\[.*\] - \d+ \d+ - GET https? .* ".*(/\.env|/\.git|/\.aws|/\.ssh|/config|/backup|wp-config|phpinfo|admin/config|server-status|server-info).*" \[Client \] ^\[.*\] - 40\d \d+ - GET https? .* ".*\.(php|asp|jsp|cgi|pl|py).*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*\.\.\/.*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*(union|select|insert|update|delete|drop|create|alter).*" \[Client \] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(\] ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*(\||`|;|<|>|\\|\{|\}|\[|\]).*" \[Client \] ^\[.*\] - \d+ \d+ - GET https? .* ".*/(etc/|var/|bin/|usr/bin/|tmp/|proc/).*" \[Client \] ignoreregex = EOF # Фильтр 404 cat > /opt/fail2ban/config/filter.d/nginx-404-flood.conf << 'EOF' [Definition] failregex = ^\[.*\] - 404 \d+ - (GET|POST|HEAD) https? .* ".*" \[Client \] ignoreregex = EOF # Фильтр DoS cat > /opt/fail2ban/config/filter.d/nginx-dos-block.conf << 'EOF' [Definition] failregex = ^\[.*\] - \d+ \d+ - (GET|POST|HEAD) https? .* ".*" \[Client \] ignoreregex = ^\[.*\] - \d+ \d+ - (GET|POST) https? .* ".*\.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg).*" \[Client \] EOF # Символические ссылки ln -sf /opt/fail2ban/config/filter.d/nginx-scan-block.conf /etc/fail2ban/filter.d/ ln -sf /opt/fail2ban/config/filter.d/nginx-404-flood.conf /etc/fail2ban/filter.d/ ln -sf /opt/fail2ban/config/filter.d/nginx-dos-block.conf /etc/fail2ban/filter.d/ ==== Создание конфигурации jail ==== **ВАЖНО:** Замените IP адреса в параметре ''ignoreip'' на свои. cat > /opt/fail2ban/config/jail.d/nginx-protection.conf << 'EOF' [DEFAULT] bantime = 3600 findtime = 300 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 ln -sf /opt/fail2ban/config/jail.d/nginx-protection.conf /etc/fail2ban/jail.d/ ==== Тестирование и запуск ==== # Тест конфигурации fail2ban-client -t # Тест фильтров fail2ban-regex /opt/fail2ban/logs/nginx-access.log /opt/fail2ban/config/filter.d/nginx-scan-block.conf # Запуск systemctl enable fail2ban systemctl start fail2ban systemctl status fail2ban ===== Проверка работы ===== # Статус jail fail2ban-client status fail2ban-client status nginx-scan-block # Правила iptables iptables -L -n | grep nginx iptables -L f2b-nginx-scan -n -v ===== Управление ===== ==== Проверка статуса ==== fail2ban-client status fail2ban-client status nginx-scan-block ==== Разбан IP ==== fail2ban-client unban 1.2.3.4 fail2ban-client set nginx-scan-block unbanip 1.2.3.4 ==== Ручной бан ==== fail2ban-client set nginx-scan-block banip 1.2.3.4 ==== Просмотр логов ==== tail -f /var/log/fail2ban.log tail -f /opt/fail2ban/logs/parser.log tail -100 /var/log/fail2ban.log | grep -E "Ban|Unban" ===== Настройка параметров ===== ^ Параметр ^ Описание ^ Значение ^ | maxretry | Попытки до бана | 3-10 для scan, 50 для DoS | | findtime | Окно поиска (секунды) | 300 (5 минут) | | bantime | Время бана (секунды) | 3600-7200 (1-2 часа) | Файл: ''/opt/fail2ban/config/jail.d/nginx-protection.conf'' После изменений: systemctl restart fail2ban ===== Troubleshooting ===== ==== Fail2ban не запускается ==== journalctl -xeu fail2ban fail2ban-client -d ==== Jail не банит ==== fail2ban-client status nginx-scan-block Должно быть: ''File list: /opt/fail2ban/logs/nginx-access.log'' Если ''Journal matches'' - добавьте ''backend = polling'' в jail. ==== Фильтры не работают ==== 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 ==== Парсер не работает ==== bash -x /opt/fail2ban/scripts/parse-nginx-logs.sh cat /opt/fail2ban/logs/parser.log ls -la /opt/nginxpm/data/logs/ docker ps | grep nginxpm ===== Резервное копирование ===== tar -czf fail2ban-backup-$(date +%Y%m%d).tar.gz \ /opt/fail2ban/config/ \ /opt/fail2ban/scripts/ ===== Удаление ===== 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-*.conf crontab -e # Удалить строку с parse-nginx-logs.sh iptables -F ===== Полезные ссылки ===== * [[https://www.fail2ban.org/|Официальный сайт Fail2ban]] * [[https://github.com/fail2ban/fail2ban|GitHub репозиторий]] * [[https://nginxproxymanager.com/|Nginx Proxy Manager]] ---- **Автор:** Nick\\ **Дата создания:** 2025-11-30\\ **Последнее обновление:** 2025-11-30