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

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

Посетите 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 параметры

Контекст: 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 Too Many Requests 5. Если установлен autoban, IP добавляется в указанный набор nft

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

JavaScript Challenge

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 задачу        │
│   │    вызова     │                                                  │
│   └───────┬───────┘                                                  │
│           │ Пройдено                                                 │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  Проверка     │────▶│   ПОПАДАНИЕ │────▶ Использовать кэшированный результат │
│   │     кэша     │     └─────────────┘                             │
│   └───────┬───────┘                                                  │
│           │ ПРОМАХ                                                  │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  Запрос к     │──── Контекст libnftables, локальный для потока  │
│   │   nft (ядро)  │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ Сохранить в   │                                                  │
│   │    кэш        │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    Решение     │──── Совпадение в черном списке? ────▶ Блокировать (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 предотвращает использование /usr/sbin/nginx 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