Перейти к содержанию

ipset-access: Блокировка IP с нулевой задержкой с использованием ipsets ядра Linux (v2)

Требуется план Pro (или выше) подписки GetPageSpeed NGINX Extras.

Установка

Вы можете установить этот модуль в любом дистрибутиве на базе RHEL, включая, но не ограничиваясь:

  • RedHat Enterprise Linux 7, 8, 9 и 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-ipset-access
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-ipset-access

Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:

load_module modules/ngx_http_ipset_access_module.so;

Этот документ описывает nginx-module-ipset-access v2.0.10, выпущенный 13 июня 2026 года.


IP-контроль доступа корпоративного уровня для NGINX с использованием ipset Linux. Блокируйте угрозы, ограничивайте злоумышленников, ставьте задачи для ботов и защищайте свою инфраструктуру.

Version GetPageSpeed

⚠️ Коммерческое программное обеспечение
Это закрытый премиум модуль, доступный исключительно через GetPageSpeed Repository.

Требование к плану: Требуется план Pro подписки GetPageSpeed NGINX Extras.

✨ Особенности

Основные функции

Функция Описание
Черный/Белый список Разрешить или запретить на основе членства в ipset
Несколько ipset Проверка по нескольким ipset в одной директиве
Живые обновления Изменение ipset без перезагрузки NGINX
Пользовательские коды состояния Возвращать любой HTTP статус при блокировке

Функции производительности

Функция Описание
Сессии на поток Локальные для потока сессии libipset устраняют конкуренцию за блокировки
Кэш LRU Кэш в общей памяти с настраиваемым TTL
Коэффициенты попадания в кэш Обычно 95%+ коэффициент попадания снижает вызовы ядра

Функции безопасности

Функция Описание
Ограничение скорости Ограничение запросов на IP с настраиваемыми окнами
Авто-бан Автоматически добавляет нарушителей в черный список
JS Challenge Задача на доказательство работы останавливает автоматизированные боты
Ловушки для меда Авто-блокировка IP, попадающих на ловушки URL
Тайм-аут входа Авто-истечение записей черного списка

Операционные функции

Функция Описание
Режим пробного запуска Тестирование конфигурации без блокировки
Fail-open/close Управление поведением при ошибках ipset
Метрики Prometheus Нативная конечная точка /metrics для Grafana
JSON статистика Подробный API статистики
Переменные NGINX $ipset_result и $ipset_matched_set
##

🚀 Быстрый старт

1. Создайте ipsets

# Создать черный список
sudo ipset create bad_guys hash:ip timeout 86400

# Создать список банов для ограничения скорости  
sudo ipset create ratelimited hash:ip timeout 1800

# Создать список ловушек для меда
sudo ipset create honeypot hash:ip timeout 86400

2. Настройте NGINX

load_module modules/ngx_http_ipset_access_module.so;

http {
    server {
        listen 80;

        # Блокировать известные плохие IP
        ipset_blacklist bad_guys;

        # Ограничение скорости: 100 запросов в минуту
        ipset_ratelimit rate=100 window=60s autoban=ratelimited;

        # Ваш контент
        location / {
            root /var/www/html;
        }

        # Ловушка для меда - по умолчанию возвращает 404
        location /wp-admin.php {
            ipset_autoadd honeypot timeout=86400;
        }

        # Конечная точка метрик
        location /metrics {
            ipset_metrics;
            allow 127.0.0.1;
            deny all;
        }
    }
}

3. Протестируйте и перезагрузите

sudo nginx -t && sudo nginx -s reload

📦 Установка

Этот модуль доступен исключительно через GetPageSpeed Premium Repository.

Шаг 1: Подпишитесь на репозиторий GetPageSpeed

Посетите GetPageSpeed Repository Subscription, чтобы получить доступ.

Шаг 2: Установите репозиторий

# RHEL/CentOS/Rocky/Alma Linux 8+
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm

Шаг 3: Установите модуль

sudo dnf install nginx-module-ipset-access

Шаг 4: Включите модуль

Добавьте в /etc/nginx/nginx.conf перед любыми блоками http {}:

load_module modules/ngx_http_ipset_access_module.so;

Шаг 5: Перезагрузите NGINX

sudo nginx -t && sudo systemctl reload nginx

📖 Справочник по конфигурации

Контроль доступа

ipset_blacklist set1 [set2 ...]

Контекст: http, server
По умолчанию:

Блокирует запросы, если IP клиента появляется в любом из указанных ipset. Несколько ipset проверяются по порядку, пока не будет найдено совпадение.

# Один набор
ipset_blacklist bad_guys;

# Несколько наборов (логика ИЛИ - заблокирован, если в ЛЮБОМ наборе)
ipset_blacklist spammers hackers tor_exits;

# Отключить
ipset_blacklist off;

ipset_whitelist set1 [set2 ...]

Контекст: http, server
По умолчанию:

Разрешает запросы только если IP клиента появляется хотя бы в одном из указанных ipset. Все другие IP отклоняются.

# Разрешить только доверенные IP
ipset_whitelist trusted_partners office_ips;

Важно: IP в белом списке обходят все ограничения модуля, включая: - Ограничение скорости (ipset_ratelimit) - Задачи на JavaScript (ipset_challenge)

Это полезно для IP администраторов, которые не должны подлежать ограничениям по скорости или задачам:

# IP администраторов обходят ограничения по скорости и задачи
ipset_whitelist admin_ips;
ipset_ratelimit rate=100 window=1m autoban=ratelimited ban_time=1800;
ipset_challenge on;

ipset_status code

Контекст: http, server
По умолчанию: 403

HTTP код состояния, возвращаемый, когда запрос заблокирован.

ipset_status 403;   # Запрещено (по умолчанию)
ipset_status 444;   # Закрыть соединение без ответа (специальный NGINX)
ipset_status 429;   # Слишком много запросов
ipset_status 503;   # Служба недоступна

Кэширование и производительность

ipset_cache_ttl time

Контекст: http, server
По умолчанию: 60s

Как долго кэшировать результаты поиска ipset. Кэшированные результаты избегают повторных вызовов ядра для одного и того же IP.

ipset_cache_ttl 30s;    # 30 секунд
ipset_cache_ttl 5m;     # 5 минут
ipset_cache_ttl 1h;     # 1 час

Примечание по отладке: Если вы удалите IP из ipset, но модуль все еще сообщает, что он "совпадает", это связано с кэшированием. Кэшированный результат истечет после установленного TTL. Для немедленного эффекта во время тестирования вы можете временно установить ipset_cache_ttl 0;, чтобы отключить кэширование (не рекомендуется для производства из-за влияния на производительность).

Влияние на производительность: - Более высокий TTL = Лучшая производительность, но медленнее отражает изменения ipset - Более низкий TTL = Более быстрая реакция на изменения ipset, но больше вызовов ядра - Рекомендуется: 30s до 5m для большинства случаев использования

ipset_fail_open on|off

Контекст: http, server
По умолчанию: off

Управляет поведением, когда поиск ipset не удался (например, набор не существует).

ipset_fail_open off;   # Запретить при ошибке (безопасно, по умолчанию)
ipset_fail_open on;    # Разрешить при ошибке (доступно, но рискованно)

ipset_dryrun on|off

Контекст: http, server
По умолчанию: off

Когда включено, ведет учет того, что было бы заблокировано, но на самом деле не блокирует. Идеально для тестирования новых правил в производстве.

ipset_dryrun on;   # Вести учет, но не блокировать

Проверьте журналы на наличие сообщений, подобных:

ipset: DRYRUN would block 1.2.3.4 (matched: bad_guys)

Важно: При использовании переменных $ipset_result и $ipset_matched_set в режиме пробного запуска эти значения отражают состояние в момент времени, когда запрос обрабатывался, а не текущее состояние ipset. Если вы позже проверите ipset вручную и не найдете IP, возможные причины включают:

  1. Истечение времени ожидания: IP был добавлен с тайм-аутом (например, timeout=86400) и с тех пор истек
  2. Задержка кэша: Модуль кэширует результаты поиска (по умолчанию 60s). Запись, удаленная из ipset, может по-прежнему отображаться как "совпадающая", пока кэш не истечет
  3. Ручное удаление: Кто-то или что-то (fail2ban, скрипты) удалило запись

Это ожидаемое поведение — пробный запуск показывает вам именно то, что видит производство в момент запроса.

Ограничение скорости

ipset_ratelimit параметры

Контекст: http, server
По умолчанию:

Ограничивает запросы на IP в пределах временного окна. Может автоматически добавлять нарушителей в ipset.

Параметры:

Параметр Обязательный Описание
rate=N Да Максимальное количество запросов за окно
window=TIME Нет Временное окно (по умолчанию: 60s)
autoban=SET Нет ipset для добавления нарушителей
ban_time=N Нет Секунды до авто-истечения (по умолчанию: 3600)

Примеры:

# Основной: 100 запросов в минуту
ipset_ratelimit rate=100;

# С настраиваемым окном: 1000 запросов в час
ipset_ratelimit rate=1000 window=1h;

# С авто-баном: Добавить нарушителей в ipset на 30 минут
ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

# Строгая защита API
ipset_ratelimit rate=10 window=1s autoban=api_abusers ban_time=3600;

Как это работает: 1. Каждый IP получает счетчик запросов и время начала окна 2. Счетчик увеличивается с каждым запросом 3. Когда окно истекает, счетчик сбрасывается 4. Если счетчик превышает rate, возвращает 429 Слишком много запросов 5. Если установлен autoban, IP добавляется в указанный ipset

Примечание: Состояние ограничения скорости хранится в общей памяти и сохраняется при перезапуске рабочих процессов.

Задача на JavaScript

ipset_challenge on|off

Контекст: http, server
По умолчанию: off

Включает режим задачи на JavaScript. Браузеры должны решить задачу на доказательство работы, чтобы получить доступ к сайту. Эффективно против автоматизированных ботов и сканеров.

ipset_challenge on;

Как это работает: 1. Первый запрос получает страницу с задачей (HTTP 503) 2. Браузер выполняет JavaScript, который решает задачу хеширования 3. Решение хранится в cookie (_ipset_verified) 4. Последующие запросы с действительным cookie проходят 5. Cookie истекает через 24 часа

ipset_challenge_difficulty level

Контекст: http, server
По умолчанию: 2

Управляет сложностью задачи (1-8). Более высокий = больше времени на решение.

Уровень Приблизительное время решения
1 ~100ms
2 ~500ms (по умолчанию)
3 ~1 секунда
4 ~2 секунды
5 ~5 секунд
6+ ~10+ секунд
ipset_challenge on;
ipset_challenge_difficulty 3;  # ~1 секунда времени решения

Особенности страницы с задачей: - Современный, адаптивный дизайн - Анимированный индикатор загрузки - Обратная связь о прогрессе - Авто-редирект при успехе - Без внешних зависимостей

Авто-добавление ловушки для меда

ipset_autoadd setname [timeout=seconds] [status=code]

Контекст: server, location
По умолчанию:

Автоматически добавляет IP клиента в указанный ipset, когда доступ к локации осуществляется и возвращается HTTP код состояния. Идеально для ловушек для меда.

Параметры:

Параметр Обязательный Описание
setname Да Имя целевого ipset
timeout=N Нет Тайм-аут записи в секундах
status=N Нет HTTP код состояния для возврата (по умолчанию: 404)

Примеры:

# Основной: Добавить в набор ловушек для меда и вернуть 404 (по умолчанию)
location /config.php {
    ipset_autoadd honeypot;
}

# С тайм-аутом: Авто-истечение через 24 часа
location /wp-admin.php {
    ipset_autoadd scanners timeout=86400;
}

# Вернуть 403 Запрещено вместо 404
location /admin.php {
    ipset_autoadd honeypot timeout=86400 status=403;
}

# Вернуть 429 Слишком много запросов
location /api/hack {
    ipset_autoadd abusers timeout=3600 status=429;
}

Общие пути ловушек для меда:

# Ловушки WordPress - вернуть 404, чтобы выглядеть как отсутствующий файл
location ~ ^/(wp-admin\.php|wp-login\.php|xmlrpc\.php)$ {
    ipset_autoadd honeypot timeout=86400;
}

# Ловушки конфигурационных файлов - вернуть 403, чтобы имитировать запрещенный доступ
location ~ ^/(\\.env|config\\.php|phpinfo\\.php)$ {
    ipset_autoadd honeypot timeout=86400 status=403;
}

# Ловушки для оболочки/эксплойта - серьезные, блокировать на 1 неделю
location ~ ^/(shell|cmd|eval|exec)\\.php$ {
    ipset_autoadd malicious timeout=604800 status=403;
}

Примечание: Когда IP автоматически добавляется, модуль немедленно возвращает указанный HTTP код состояния (по умолчанию 404), предотвращая дальнейшую обработку запроса. Также отключается keep-alive соединения, чтобы предотвратить дальнейшие запросы по тому же соединению.

Наблюдаемость

ipset_stats

Контекст: location
По умолчанию:

Включает конечную точку статистики JSON.

location = /_stats {
    ipset_stats;
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    deny all;
}

Смотрите JSON Stats API для формата ответа.

ipset_metrics

Контекст: location
По умолчанию:

Включает конечную точку метрик Prometheus.

location = /metrics {
    ipset_metrics;
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    deny all;
}

Смотрите Prometheus Metrics для доступных метрик.

📝 Переменные NGINX

Модуль предоставляет две переменные для использования в логировании, заголовках или условиях.

$ipset_result

Решение о доступе, принятое для этого запроса.

Значение Описание
allow Запрос разрешен
deny Запрос заблокирован
dryrun Было бы заблокировано (режим пробного запуска)
ratelimited Превышен лимит скорости
challenged Страница с задачей обслужена

$ipset_matched_set

Имя ipset, которое совпало (если есть). Пусто, если совпадений нет.

Примечание: Эта переменная отражает состояние совпадения в момент запроса, а не текущее состояние ipset. Если вы проверите ipset вручную и не найдете IP: - Запись могла истечь (ipset поддерживает тайм-ауты для каждой записи) - Кэш модуля (по умолчанию 60s) может показывать недавно удаленную запись как все еще совпадающую - Что-то могло удалить запись после обработки запроса

Примеры использования

Пользовательский журнал доступа:

log_format security '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    'ipset_result="$ipset_result" '
                    'matched_set="$ipset_matched_set"';

access_log /var/log/nginx/security.log security;

Добавить заголовки для отладки:

add_header X-IPSet-Result $ipset_result always;
add_header X-IPSet-Matched $ipset_matched_set always;

Условное логирование:

# Логировать только заблокированные запросы
map $ipset_result $loggable {
    "deny"  1;
    default 0;
}

access_log /var/log/nginx/blocked.log combined if=$loggable;

📊 Метрики Prometheus

Конечная точка /metrics возвращает метрики в формате экспозиции Prometheus.

Доступные метрики

# HELP nginx_ipset_requests_total Всего обработанных запросов
# TYPE nginx_ipset_requests_total counter
nginx_ipset_requests_total{result="checked"} 1234567
nginx_ipset_requests_total{result="allowed"} 1234000
nginx_ipset_requests_total{result="blocked"} 500
nginx_ipset_requests_total{result="error"} 67

# HELP nginx_ipset_cache_total Операции кэша
# TYPE nginx_ipset_cache_total counter
nginx_ipset_cache_total{result="hit"} 1200000
nginx_ipset_cache_total{result="miss"} 34567

# HELP nginx_ipset_cache_entries Текущие записи кэша
# TYPE nginx_ipset_cache_entries gauge
nginx_ipset_cache_entries 5432

# HELP nginx_ipset_autoadd_total Операции авто-добавления
# TYPE nginx_ipset_autoadd_total counter
nginx_ipset_autoadd_total{result="success"} 42
nginx_ipset_autoadd_total{result="failed"} 3

# HELP nginx_ipset_ratelimit_total События ограничения скорости
# TYPE nginx_ipset_ratelimit_total counter
nginx_ipset_ratelimit_total{action="triggered"} 156
nginx_ipset_ratelimit_total{action="autobanned"} 23

# HELP nginx_ipset_challenge_total События задач
# TYPE nginx_ipset_challenge_total counter
nginx_ipset_challenge_total{result="issued"} 1000
nginx_ipset_challenge_total{result="passed"} 950
nginx_ipset_challenge_total{result="failed"} 50

# HELP nginx_ipset_uptime_seconds Время работы модуля
# TYPE nginx_ipset_uptime_seconds gauge
nginx_ipset_uptime_seconds 86400

Запросы для панели Grafana

Скорость запросов по результату:

rate(nginx_ipset_requests_total[5m])

Скорость блокировок:

rate(nginx_ipset_requests_total{result="blocked"}[5m])

Коэффициент попадания в кэш:

rate(nginx_ipset_cache_total{result="hit"}[5m]) / 
(rate(nginx_ipset_cache_total{result="hit"}[5m]) + rate(nginx_ipset_cache_total{result="miss"}[5m]))

Триггеры ограничения скорости в минуту:

rate(nginx_ipset_ratelimit_total{action="triggered"}[1m]) * 60

📈 JSON Stats API

Конечная точка /_stats возвращает подробную статистику в формате JSON.

Формат ответа

{
  "version": "2.0.7",
  "uptime_seconds": 86400,
  "requests": {
    "checked": 1234567,
    "allowed": 1234000,
    "blocked": 500,
    "errors": 67
  },
  "cache": {
    "hits": 1200000,
    "misses": 34567,
    "entries": 5432,
    "hit_rate": 97.20
  },
  "autoadd": {
    "success": 42,
    "failed": 3
  },
  "ratelimit": {
    "triggered": 156,
    "autobanned": 23
  },
  "challenge": {
    "issued": 1000,
    "passed": 950,
    "failed": 50
  }
}

Описания полей

Поле Описание
version Версия модуля
uptime_seconds Секунды с момента загрузки модуля
requests.checked Всего обработанных запросов
requests.allowed Запросы, которые прошли
requests.blocked Запросы, которые были заблокированы
requests.errors Ошибки поиска ipset
cache.hits Попадания в кэш (избежанные вызовы ядра)
cache.misses Промахи кэша (требуемые вызовы ядра)
cache.entries Текущие записи в кэше
cache.hit_rate Процент попадания
autoadd.success Успешные добавления ловушек для меда
autoadd.failed Неудачные добавления ловушек для меда
ratelimit.triggered Нарушения ограничения скорости
ratelimit.autobanned IP, автоматически добавленные в черный список
challenge.issued Страницы с задачами обслужены
challenge.passed Задачи успешно решены
challenge.failed Ошибки задач
##

🏗️ Архитектура

┌─────────────────────────────────────────────────────────────────────┐
│                           ПОТОК ЗАПРОСОВ                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Входящий запрос                                                    │
│         │                                                            │
│         ▼                                                            │
│   ┌───────────────┐                                                  │
│   │  Проверка     │──── Превышен? ────▶ 429 + Авто-бан            │
│   │   лимита      │                                                  │
│   └───────┬───────┘                                                  │
│           │ ОК                                                       │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Проверка    │──── Нет cookie? ────▶ Обслужить JS задачу      │
│   │    задачи      │                                                  │
│   └───────┬───────┘                                                  │
│           │ Пройдено                                                │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  Проверка     │────▶│   ПОПАДАНИЕ │────▶ Использовать кэшированный результат  │
│   │   кэша       │     └─────────────┘                             │
│   └───────┬───────┘                                                  │
│           │ ПРОМАХ                                                │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  Запрос ipset │──── Локальная для потока сессия libipset       │
│   │  (ядро)       │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ Сохранить в   │                                                  │
│   │   кэш         │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    Решение     │──── Совпадение с черным списком? ────▶ Блокировать (403/444) │
│   │               │──── Промах с белым списком? ────▶ Блокировать (403/444) │
│   └───────┬───────┘                                                  │
│           │ Разрешить                                              │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Проверка    │──── Совпадение с локацией? ────▶ Добавить в ipset │
│   │    ловушки     │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│       Продолжить к                                                │
│       Обработчику контента                                        │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                        ОБЩАЯ ПАМЯТЬ                                 │
│  ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│  │     Статистика  │    Кэш LRU      │    Ведра ограничения скорости  │ │
│  │   (счетчики)   │  (IP → Результат)  │   (IP → Счетчик запросов)  │ │
│  └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

Расположение памяти

Компонент Местоположение Назначение
Сессия libipset Локальная для потока Сессия на каждого рабочего процесса для избежания блокировок
Кэш поиска Общая память Кэш LRU сопоставлений IP→результат
Ведра ограничения скорости Общая память Счетчики запросов на IP
Статистика Общая память Атомарные счетчики для метрик
##

📚 Примеры

Пример 1: Основной черный список

# Создать ipset
sudo ipset create blacklist hash:ip
sudo ipset add blacklist 1.2.3.4
    server {
    listen 80;

    ipset_blacklist blacklist;

    location / {
        root /var/www/html;
    }
}

Пример 2: API с ограничением скорости

server {
    listen 80;

    # Строгое ограничение скорости для API
    ipset_ratelimit rate=100 window=1m autoban=api_banned ban_time=3600;

    # Разрешить только известным партнерам
    ipset_whitelist api_partners;
    ipset_status 401;

    location /api/ {
        proxy_pass http://backend;
    }
}

Пример 3: Полный стек безопасности

    server {
        listen 80 default_server;

    # Уровень 1: Известные угрозы
    ipset_blacklist malware_ips tor_exits datacenter_ranges;
    ipset_status 444;
    ipset_cache_ttl 5m;

    # Уровень 2: Ограничение скорости
    ipset_ratelimit rate=60 window=1m autoban=ratelimited ban_time=1800;

    # Уровень 3: Задача для бота
    ipset_challenge on;
    ipset_challenge_difficulty 2;

    # Реальный контент
        location / {
        root /var/www/html;
    }

    # Ловушки для меда - вернуть 404 (по умолчанию), чтобы выглядеть как отсутствующие файлы
    location ~ ^/(wp-admin|phpmyadmin|admin)\.php$ {
        ipset_autoadd honeypot timeout=86400;
    }

    # Мониторинг
    location = /metrics {
        ipset_metrics;
        allow 10.0.0.0/8;
        deny all;
    }
}

Пример 4: Тестирование в режиме пробного запуска

server {
    listen 80;

    # Тестировать новые правила без блокировки
    ipset_blacklist new_threat_list;
    ipset_dryrun on;

    location / {
        root /var/www/html;
    }
}

Проверьте журналы:

tail -f /var/log/nginx/error.log | grep "DRYRUN"

🔧 Устранение неполадок

Модуль не загружается

nginx: [emerg] dlopen() failed

Решение: Убедитесь, что NGINX был собран с --with-compat, и модуль был собран для той же версии NGINX.

ipset не найден

ipset: INVALID_SETNAME

Решение: Создайте ipset перед запуском NGINX:

sudo ipset create myset hash:ip

Доступ запрещен

ipset: kernel error

Решение: Рабочий процесс NGINX должен иметь возможность CAP_NET_ADMIN:

sudo setcap cap_net_admin+ep /usr/sbin/nginx

Отказы SELinux (RHEL/CentOS/AlmaLinux)

SELinux предотвращает доступ /usr/sbin/nginx к getattr на netlink_netfilter_socket

Решение: Установите включенный модуль политики SELinux:

cd selinux/
sudo ./install.sh

Или вручную:

# Проверить
semodule -l | grep nginx_ipset

Политика позволяет httpd_t (домен SELinux NGINX) использовать сокеты netlink_netfilter, необходимые для libipset.

firewalld + nftables backend + ipset: источники (Rocky/RHEL 9)

Если вы используете firewalld с nftables по умолчанию и пытаетесь прикрепить управляемые модулем ipsets к зонам с:

firewall-cmd --permanent --zone=drop --add-source=ipset:honeypot4
firewall-cmd --reload

это может завершиться ошибками при перезагрузке, такими как:

COMMAND_FAILED: 'python-nftables' failed: ... Error: No such file or directory

Причина (кратко): Бэкенд nftables firewalld использует nft sets для источников ipset:, в то время как этот модуль использует kernel ipsets через libipset. Это разные подсистемы, поэтому они не взаимодействуют.

Рекомендация: Если вы хотите, чтобы "блокировка перед NGINX" была обеспечена авто-банами этого модуля, настройте firewalld на использование iptables backend:

sudo sed -i 's/^FirewallBackend=.*/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
sudo systemctl restart firewalld
sudo firewall-cmd --reload

Идея на будущее: Отдельный модуль, который взаимодействует с наборами nftables (например, "nfset-access"), мог бы поддерживать бэкенд nft firewalld нативно, но это потребует библиотек/API nftables и выходит за рамки этого модуля только для libipset.

Высокое использование памяти

Решение: Уменьшите TTL кэша или ограничьте размер кэша в конфигурации общей памяти.

Ограничение скорости не работает

Решение: Убедитесь, что ipset для авто-банов существует и поддерживает тайм-аут:

sudo ipset create ratelimited hash:ip timeout 3600

Журнал показывает "matched=setname", но IP не в ipset

Это ожидаемое поведение. Модуль сообщает то, что он увидел в момент запроса. Если вы позже проверите ipset вручную и не найдете IP:

  1. Истечение времени ожидания: IP был добавлен с тайм-аутом и с тех пор истек

    # Проверьте, поддерживает ли набор тайм-ауты
    ipset list setname | head -5
    # Ищите "timeout" в заголовке
    

  2. Кэш модуля: Модуль кэширует результаты поиска (по умолчанию 60s). Недавно удаленный IP может по-прежнему отображаться как "совпадающий"

    # Временно отключить кэш для отладки (не для производства!)
    ipset_cache_ttl 0;
    

  3. Запись была удалена: fail2ban, скрипты или ручные команды могли удалить ее

  4. Проблема с конфигурацией ловушки: Если вы используете ловушки для меда с ipset_autoadd, законные боты могли активировать ловушки. Проверьте, чтобы ваши пути ловушек не пересекались с законными путями ботов (такими как карты сайта, robots.txt). Используйте robots.txt, чтобы исключить пути ловушек из обхода.

autoadd не удается с "result=4"

Это означает, что вы используете timeout=N в ipset_autoadd, но ipset был создан без поддержки тайм-аутов.

Решение: Воссоздайте ipset с поддержкой тайм-аутов:

# Используя ipset напрямую
sudo ipset destroy honeypot4
sudo ipset create honeypot4 hash:ip family inet timeout 86400

# Используя firewall-cmd (RHEL/CentOS/Amazon Linux)
sudo firewall-cmd --permanent --delete-ipset=honeypot4
sudo firewall-cmd --permanent --new-ipset=honeypot4 --type=hash:ip \
    --option=family=inet --option=timeout=86400
sudo firewall-cmd --reload

📋 Требования

  • NGINX ≥ 1.22 (собранный с --with-compat)
  • Ядро Linux с поддержкой ipset (ip_set + поддержка netfilter/x_tables; обычно доступно на RHEL/Rocky/Alma/Amazon Linux)
  • Библиотека libipset и заголовки разработки
  • Возможности: CAP_NET_ADMIN для операций ipset

📜 Лицензия

Это программное обеспечение является собственностью. Все права защищены.

Доступно исключительно через GetPageSpeed Premium Repository.

👤 Автор

Данила Верши́нин
GetPageSpeed LLC

🆘 Поддержка

Модуль доступа NGINX IPSet
Премиум модуль NGINX от GetPageSpeed LLC
www.getpagespeed.com