跳转至

nftset-access: 使用 Linux 内核 nftables 集实现零延迟 IP 阻止

需要 GetPageSpeed NGINX Extras 订阅的 Pro 计划(或更高版本)。

安装

您可以在任何基于 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,于 2026 年 2 月 14 日发布。


企业级基于 IP 的 NGINX 访问控制,使用 Linux nftables 集。阻止威胁、限制滥用者的请求、挑战机器人并保护您的基础设施。

版本 GetPageSpeed

⚠️ 商业软件 这是一个封闭源代码的高级模块,仅通过 GetPageSpeed Repository 提供。

计划要求: 需要 GetPageSpeed NGINX Extras 订阅的 Pro 计划。

✨ 特性

核心特性

特性 描述
白名单/黑名单 根据 nftables 集成员资格允许或拒绝
多个集合 在一个指令中检查多个 nft 集
实时更新 修改 nft 集而无需重新加载 NGINX
自定义状态码 阻止时返回任何 HTTP 状态
CIDR 支持 使用区间集表示网络范围(例如,192.168.1.0/24)

性能特性

特性 描述
每线程会话 线程本地的 libnftables 上下文消除锁竞争
LRU 缓存 具有可配置 TTL 的共享内存缓存
缓存命中率 通常 95%+ 的命中率减少内核调用

安全特性

特性 描述
速率限制 限制每个 IP 的请求,具有可配置的窗口
自动禁用 自动将速率限制违规者列入黑名单
JS 挑战 工作量证明挑战阻止自动化机器人
蜜罐陷阱 自动将访问陷阱 URL 的 IP 列入黑名单
条目超时 自动过期黑名单条目

操作特性

特性 描述
干运行模式 测试配置而不进行阻止
失败开放/关闭 控制 nft 集错误时的行为
Prometheus 指标 Grafana 的本地 /metrics 端点
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:安装 Repository

## 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:启用模块

在任何 http {} 块之前添加到 /etc/nginx/nginx.conf

load_module modules/ngx_http_nftset_access_module.so;

步骤 5:重新加载 NGINX

sudo nginx -t && sudo systemctl reload nginx

📖 配置参考

集规范格式

所有引用 nftables 集的指令使用格式:table:setname

  • table — nftables 表名称(例如,filterfirewalld
  • 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 ...]

上下文: httpserver 默认:

如果客户端 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 ...]

上下文: httpserver 默认:

仅当客户端 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

上下文: httpserver 默认: 403

请求被阻止时返回的 HTTP 状态码。

nftset_status 403;   # 禁止(默认)
nftset_status 444;   # 关闭连接而不响应(NGINX 特殊)
nftset_status 429;   # 请求过多
nftset_status 503;   # 服务不可用

缓存与性能

nftset_cache_ttl time

上下文: httpserver 默认: 60s

缓存 nft 集查找结果的时间。缓存结果避免对相同 IP 的重复内核调用。

nftset_cache_ttl 30s;    # 30 秒
nftset_cache_ttl 5m;     # 5 分钟
nftset_cache_ttl 1h;     # 1 小时

调试注意: 如果您从 nft 集中移除一个 IP,但模块仍报告其为“匹配”,这是由于缓存。缓存结果将在配置的 TTL 过期后失效。在测试期间,您可以暂时设置 nftset_cache_ttl 0; 来禁用缓存(由于性能影响,不建议在生产中使用)。

性能影响: - 较高的 TTL = 更好的性能,但反映 nft 集更改的速度较慢 - 较低的 TTL = 对 nft 集更改的响应更快,但更多的内核调用 - 推荐:对于大多数用例,设置为 30s5m

nftset_fail_open on|off

上下文: httpserver 默认: off

控制 nft 集查找失败时的行为(例如,集合不存在)。

nftset_fail_open off;   # 出错时拒绝(安全,默认)
nftset_fail_open on;    # 出错时允许(可用但有风险)

nftset_dryrun on|off

上下文: httpserver 默认: 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

上下文: httpserver 默认:

在时间窗口内限制每个 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 挑战

nftset_challenge on|off

上下文: httpserver 默认: off

启用 JavaScript 挑战模式。浏览器必须解决工作量证明难题才能访问网站。对自动化机器人和抓取工具有效。

nftset_challenge on;

工作原理: 1. 第一次请求收到一个挑战页面(HTTP 503) 2. 浏览器执行 JavaScript 解决哈希难题 3. 解决方案存储在 cookie 中(_nftset_verified) 4. 随后的请求带有有效 cookie 的通过 5. Cookie 在 24 小时后过期

nftset_challenge_difficulty level

上下文: httpserver 默认: 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]

上下文: serverlocation 默认:

当访问该位置并返回 HTTP 状态码时,自动将客户端 IP 添加到指定的 nft 集。非常适合蜜罐陷阱。

参数:

参数 必需 描述
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;
}

## Shell/漏洞陷阱 - 严重,阻止 1 周
location ~ ^/(shell|cmd|eval|exec)\.php$ {
    nftset_autoadd filter:malicious timeout=604800 status=403;
}

注意: 当 IP 被自动添加时,模块立即返回指定的 HTTP 状态码(默认 404),防止进一步的请求处理。连接的保持活动也被禁用,以防止在同一连接上进行进一步请求。

可观察性

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 展示格式返回指标。

可用指标

## 帮助 nginx_nftset_requests_total 总请求处理
## 类型 nginx_nftset_requests_total 计数器
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

## 帮助 nginx_nftset_cache_total 缓存操作
## 类型 nginx_nftset_cache_total 计数器
nginx_nftset_cache_total{result="hit"} 1200000
nginx_nftset_cache_total{result="miss"} 34567

## 帮助 nginx_nftset_cache_entries 当前缓存条目
## 类型 nginx_nftset_cache_entries 计量器
nginx_nftset_cache_entries 5432

## 帮助 nginx_nftset_autoadd_total 自动添加操作
## 类型 nginx_nftset_autoadd_total 计数器
nginx_nftset_autoadd_total{result="success"} 42
nginx_nftset_autoadd_total{result="failed"} 3

## 帮助 nginx_nftset_ratelimit_total 速率限制事件
## 类型 nginx_nftset_ratelimit_total 计数器
nginx_nftset_ratelimit_total{action="triggered"} 156
nginx_nftset_ratelimit_total{action="autobanned"} 23

## 帮助 nginx_nftset_challenge_total 挑战事件
## 类型 nginx_nftset_challenge_total 计数器
nginx_nftset_challenge_total{result="issued"} 1000
nginx_nftset_challenge_total{result="passed"} 950
nginx_nftset_challenge_total{result="failed"} 50

## 帮助 nginx_nftset_uptime_seconds 模块运行时间
## 类型 nginx_nftset_uptime_seconds 计量器
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 统计 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 + 自动禁用                  │
│   │    检查      │                                                  │
│   └───────┬───────┘                                                  │
│           │ OK                                                       │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   挑战       │──── 没有 cookie? ────▶ 提供 JS 难题            │
│   │    检查      │                                                  │
│   └───────┬───────┘                                                  │
│           │ 通过                                                   │
│           ▼                                                          │
│   ┌───────────────┐     ┌─────────────┐                             │
│   │  缓存检查    │────▶│   命中      │────▶ 使用缓存结果          │
│   └───────┬───────┘     └─────────────┘                             │
│           │ 未命中                                                 │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │  nft 查询     │──── 线程本地 libnftables 上下文                │
│   │  (内核)     │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │ 存储在缓存中  │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │    决策      │──── 黑名单匹配? ────▶ 阻止(403/444)          │
│   │               │──── 白名单未命中? ────▶ 阻止(403/444)      │
│   └───────┬───────┘                                                  │
│           │ 允许                                                    │
│           ▼                                                          │
│   ┌───────────────┐                                                  │
│   │   蜜罐       │──── 位置匹配? ────▶ 添加到 nft 集              │
│   │    检查      │                                                  │
│   └───────┬───────┘                                                  │
│           │                                                          │
│           ▼                                                          │
│       继续到                                                    │
│       内容处理程序                                              │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                        共享内存                                   │
│  ┌────────────────┬─────────────────┬─────────────────────────────┐ │
│  │     统计      │    LRU 缓存     │    速率限制桶               │ │
│  │   (计数器)   │  (IP → 结果)  │   (IP → 请求计数)         │ │
│  └────────────────┴─────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

内存布局

组件 位置 目的
libnftables 上下文 线程本地 每个工作进程的上下文,以避免锁
查找缓存 共享内存 IP→结果映射的 LRU 缓存
速率限制桶 共享内存 每个 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;

    # 第一层:已知威胁
    nftset_blacklist filter:malware_ips filter:tor_exits filter:datacenter_ranges;
    nftset_status 444;
    nftset_cache_ttl 5m;

    # 第二层:速率限制
    nftset_ratelimit rate=60 window=1m autoban=filter:ratelimited ban_time=1800;

    # 第三层:机器人挑战
    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

解决方案: 在启动 NGINX 之前创建 nft 表和集合:

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(NGINX 的 SELinux 域)使用 libnftables 所需的 netlink_netfilter 套接字。

高内存使用

解决方案: 减少缓存 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 失败并出现超时错误

这意味着您在 nftset_autoadd 中使用了 timeout=N,但 nft 集是在 没有 超时支持的情况下创建的。

解决方案: 重新创建支持超时的 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. 将 ipsets 转换为 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(内核 ipsets) 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 提供。

👤 作者

Danila Vershinin GetPageSpeed LLC

🆘 支持

NGINX NFTSet Access Module
GetPageSpeed LLC 提供的高级 NGINX 模块
www.getpagespeed.com