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

nftset-access: Блокировка IP с нулевой задержкой с использованием наборов nftables ядра Linux

Требуется подписка 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-nftset-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-nftset-access

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

load_module modules/ngx_http_nftset_access.so;

Этот документ описывает nginx-module-nftset-access v3.0.0, выпущенный 14 февраля 2026 года.


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

Version GetPageSpeed

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

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

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

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

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

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

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

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

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

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

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

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

1. Создайте наборы nftables

# Создать таблицу (если не существует)
sudo nft add table ip filter

# Создать черный список с поддержкой таймаута
sudo nft add set ip filter bad_guys '{ type ipv4_addr; flags timeout; timeout 1d; }'

# Создать список для блокировки по ограничению скорости
sudo nft add set ip filter ratelimited '{ type ipv4_addr; flags timeout; timeout 30m; }'

# Создать список ловушек для меда
sudo nft add set ip filter honeypot '{ type ipv4_addr; flags timeout; timeout 1d; }'

# Создать белый список с поддержкой CIDR
sudo nft add set ip filter trusted '{ type ipv4_addr; flags interval; }'
sudo nft add element ip filter trusted '{ 10.0.0.0/8, 192.168.0.0/16 }'

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

load_module modules/ngx_http_nftset_access_module.so;

http {
    server {
        listen 80;

        # Блокировать известные плохие IP (формат: table:setname)
        nftset_blacklist filter:bad_guys;

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

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

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

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

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

sudo nginx -t && sudo nginx -s reload

📦 Установка

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

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

Посетите 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-nftset-access

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

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

load_module modules/ngx_http_nftset_access_module.so;

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

sudo nginx -t && sudo systemctl reload nginx

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

Формат спецификации набора

Все директивы, которые ссылаются на наборы nftables, используют формат: table:setname

  • table — Имя таблицы nftables (например, filter, firewalld)
  • setname — Имя набора в этой таблице

Семейство IP (ip для IPv4, ip6 для IPv6) автоопределяется по IP-адресу клиента.

Примеры:

nftset_blacklist filter:blocklist;           # IPv4 клиент → ip filter blocklist
                                             # IPv6 клиент → ip6 filter blocklist
nftset_whitelist filter:trusted;
nftset_autoadd filter:honeypot timeout=3600;

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

nftset_blacklist table:set1 [table:set2 ...]

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

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

# Один набор
nftset_blacklist filter:bad_guys;

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

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

nftset_whitelist table:set1 [table:set2 ...]

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

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

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

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

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

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

nftset_status code

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

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

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

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

nftset_cache_ttl time

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

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

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

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

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

nftset_fail_open on|off

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

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

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

nftset_dryrun on|off

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

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

nftset_dryrun on;   # Журналировать, но не блокировать

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

nftset: DRYRUN would block 1.2.3.4 (matched: filter:bad_guys)

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

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

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

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

nftset_ratelimit parameters

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

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

Параметры:

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

Примеры:

# Базовый: 100 запросов в минуту
nftset_ratelimit rate=100;

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

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

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

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

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

Задача на JavaScript

nftset_challenge on|off

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

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

nftset_challenge on;

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

nftset_challenge_difficulty level

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

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

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

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

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

nftset_autoadd table:setname [table:setname2 ...] [timeout=seconds] [status=code]

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

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

Параметры:

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

Примеры:

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

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

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

# Добавить в несколько наборов (IPv4 и IPv6)
location /trap {
    nftset_autoadd filter:honeypot4 filter:honeypot6 timeout=86400;
}

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

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

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

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

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

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

nftset_stats

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

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

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

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

nftset_metrics

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

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

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

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

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

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

$nftset_result

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

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

$nftset_matched_set

Имя набора nft, который совпал (если есть), в формате table:setname. Пусто, если совпадений нет.

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

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

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

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

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

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

add_header X-NFTSet-Result $nftset_result always;
add_header X-NFTSet-Matched $nftset_matched_set always;

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

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

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

📊 Метрики Prometheus

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

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

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

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

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

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

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

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

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

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

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

rate(nginx_nftset_requests_total[5m])

Частота блокировок:

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

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

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

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

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

📈 JSON Stats API

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

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

{
  "version": "3.0.0",
  "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 Ошибки поиска набора nft
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 + Авто-бан              │
│   │  ограничения   │                                                  │
│   └───────┬───────┘                                                  │
│           │ ОК                                                       │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Проверка    │──── Нет куки? ────▶ Обслужить JS задачу        │
│   │    задачи     │                                                  │
│   └───────┬───────┘                                                  │
│           │ Пройдено                                                 │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  Проверка кэша│────▶│   ПОПАДАНИЕ │────▶ Использовать кэшированный результат      │
│   └───────┬───────┘     └─────────────┘                             │
│           │ ПРОМАХ                                              │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  Запрос к nft │──── Контекст libnftables, локальный для потока            │
│   │  (ядро)       │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ Сохранить в кэш│                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    Решение    │──── Совпадение в черном списке? ────▶ Блокировать (403/444)      │
│   │               │──── Промах в белом списке?  ────▶ Блокировать (403/444)      │
│   └───────┬───────┘                                                  │
│           │ Разрешить                                                    │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   Проверка    │──── Совпадение местоположения? ────▶ Добавить в набор nft        │
│   │    ловушки    │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│       Продолжить к                                                  │
│       Обработчику контента                                          │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                        ОБЩАЯ ПАМЯТЬ                                 │
│  ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│  │     Статистика  │    Кэш LRU     │    Ведра ограничения скорости  │ │
│  │   (счетчики)   │  (IP → Результат)  │   (IP → Счетчик запросов)      │ │
│  └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

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

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

📚 Примеры

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

# Создать таблицу и набор nft
sudo nft add table ip filter
sudo nft add set ip filter blacklist '{ type ipv4_addr; }'
sudo nft add element ip filter blacklist '{ 1.2.3.4 }'
server {
    listen 80;

    nftset_blacklist filter:blacklist;

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

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

server {
    listen 80;

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

    # Разрешить только известным партнерам
    nftset_whitelist filter:api_partners;
    nftset_status 401;

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

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

server {
    listen 80 default_server;

    # Уровень 1: Известные угрозы
    nftset_blacklist filter:malware_ips filter:tor_exits filter:datacenter_ranges;
    nftset_status 444;
    nftset_cache_ttl 5m;

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

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

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

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

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

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

server {
    listen 80;

    # Тестирование новых правил без блокировки
    nftset_blacklist filter:new_threat_list;
    nftset_dryrun on;

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

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

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

Пример 5: Белый список CIDR (диапазоны сети)

# Создать интервальный набор для диапазонов CIDR
sudo nft add table ip filter
sudo nft add set ip filter trusted '{ type ipv4_addr; flags interval; }'
sudo nft add element ip filter trusted '{ 192.168.1.0/24, 10.0.0.0/8 }'

# Версия для IPv6
sudo nft add table ip6 filter
sudo nft add set ip6 filter trusted6 '{ type ipv6_addr; flags interval; }'
sudo nft add element ip6 filter trusted6 '{ 2001:db8::/32 }'
server {
    listen 80;

    # Белый список целых сетей
    nftset_whitelist filter:trusted;

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

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

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

nginx: [emerg] dlopen() failed

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

Набор nft не найден

nftset: set 'filter:myset' does not exist

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

sudo nft add table ip filter
sudo nft add set ip filter myset '{ type ipv4_addr; }'

Совет: Список доступных наборов:

nft list sets

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

nftset: kernel error

Решение: Рабочий процесс NGINX нуждается в праве CAP_NET_ADMIN:

sudo setcap cap_net_admin+ep /usr/sbin/nginx

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

SELinux is preventing /usr/sbin/nginx from using netlink_netfilter_socket

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

cd selinux/
sudo ./install.sh

Или вручную:

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

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

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

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

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

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

sudo nft add table ip filter
sudo nft add set ip filter ratelimited '{ type ipv4_addr; flags timeout; timeout 1h; }'

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

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

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

    # Проверьте флаги набора
    nft list set ip filter setname
    # Ищите "flags timeout" в выводе
    

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

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

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

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

autoadd не работает с ошибкой таймаута

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

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

# Удалите и воссоздайте с флагом таймаута
sudo nft delete set ip filter honeypot
sudo nft add set ip filter honeypot '{ type ipv4_addr; flags timeout; timeout 1d; }'

🔄 Миграция с ipset-access

Если вы мигрируете с более старого ngx_http_ipset_access_module, выполните следующие шаги:

1. Преобразуйте ipset в наборы nft

# Старый ipset
ipset create bad_guys hash:ip timeout 86400

# Новый эквивалент набора nft
nft add table ip filter
nft add set ip filter bad_guys '{ type ipv4_addr; flags timeout; timeout 1d; }'

# Для диапазонов CIDR (hash:net → флаг interval)
# Старый: ipset create networks hash:net
# Новый:
nft add set ip filter networks '{ type ipv4_addr; flags interval; }'

2. Обновите конфигурацию NGINX

Старый (ipset) Новый (nftset)
ipset_blacklist bad_guys; nftset_blacklist filter:bad_guys;
ipset_whitelist trusted; nftset_whitelist filter:trusted;
ipset_autoadd honeypot timeout=3600; nftset_autoadd filter:honeypot timeout=3600;
ipset_ratelimit rate=100 autoban=ratelimited; nftset_ratelimit rate=100 autoban=filter:ratelimited;
ipset_challenge on; nftset_challenge on;
ipset_challenge_difficulty 3; nftset_challenge_difficulty 3;
ipset_dryrun on; nftset_dryrun on;
ipset_fail_open on; nftset_fail_open on;
ipset_cache_ttl 60s; nftset_cache_ttl 60s;
ipset_status 403; nftset_status 403;
ipset_stats; nftset_stats;
ipset_metrics; nftset_metrics;
$ipset_result $nftset_result
$ipset_matched_set $nftset_matched_set

3. Обновите форматы журналов

# Старый
log_format security '... ipset_result="$ipset_result" matched_set="$ipset_matched_set"';

# Новый
log_format security '... nftset_result="$nftset_result" matched_set="$nftset_matched_set"';

4. Обновите запросы Prometheus/Grafana

Старая метрика Новая метрика
nginx_ipset_requests_total nginx_nftset_requests_total
nginx_ipset_cache_total nginx_nftset_cache_total
nginx_ipset_cache_entries nginx_nftset_cache_entries
nginx_ipset_autoadd_total nginx_nftset_autoadd_total
nginx_ipset_ratelimit_total nginx_nftset_ratelimit_total
nginx_ipset_challenge_total nginx_nftset_challenge_total
nginx_ipset_uptime_seconds nginx_nftset_uptime_seconds

5. Ключевые различия

Функция ipset-access nftset-access
Бэкенд libipset (ядро ipset) libnftables (nftables)
Формат набора setname table:setname
CIDR наборы тип hash:net флаг flags interval
Семейство Указано в типе набора Автоопределяется по IP клиента
firewalld только бэкенд iptables совместим с бэкендом nftables

Почему мигрировать?

  • Совместимость с RHEL 9/Rocky 9: firewalld по умолчанию использует бэкенд nftables
  • Поддержка современного ядра: nftables — это будущее брандмауэра Linux
  • Единое управление: Используйте команды nft как для брандмауэра, так и для контроля доступа
  • Лучшая поддержка CIDR: Интервальные наборы эффективно обрабатывают диапазоны сети

📋 Требования

  • NGINX ≥ 1.22 (собран с --with-compat)
  • Ядро Linux с поддержкой nftables
  • Библиотека libnftables и заголовки разработки
  • Привилегии: CAP_NET_ADMIN для операций с nftables

📜 Лицензия

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

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

👤 Автор

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

🆘 Поддержка

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