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 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 表名称(例如,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 小时
调试注意: 如果您从 nft 集中移除一个 IP,但模块仍报告其为“匹配”,这是由于缓存。缓存结果将在配置的 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,可能的原因包括:
- 超时过期:该 IP 是在超时情况下添加的(例如,
timeout 1d),并且已经过期 - 缓存延迟:模块缓存查找结果(默认 60s)。从 nft 集中移除的条目可能仍会显示为“匹配”,直到缓存过期
- 手动移除:某人或某物(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 Too Many Requests
5. 如果设置了 autoban,则将 IP 添加到指定的 nft 集
注意: 速率限制状态存储在共享内存中,并在工作进程重启时保持。
JavaScript 挑战
nftset_challenge on|off
上下文: http,server
默认: off
启用 JavaScript 挑战模式。浏览器必须解决工作量证明难题才能访问网站。对自动化机器人和抓取工具有效。
nftset_challenge on;
工作原理:
1. 第一次请求收到一个挑战页面(HTTP 503)
2. 浏览器执行 JavaScript 解决哈希难题
3. 解决方案存储在 cookie 中(_nftset_verified)
4. 随后的请求带有有效 cookie 的通过
5. Cookie 在 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
默认: —
当访问该位置并返回 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:
-
超时过期: 该 IP 是在超时情况下添加的,并且已经过期
# 检查集合标志 nft list set ip filter setname # 查找输出中的 "flags timeout" -
模块缓存: 模块缓存查找(默认 60s)。最近移除的 IP 可能仍然显示为“匹配”
# 临时禁用缓存以进行调试(不适合生产!) nftset_cache_ttl 0; -
条目被移除: fail2ban、脚本或手动命令可能已移除它
-
陷阱配置问题: 如果使用蜜罐陷阱并且
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
🆘 支持
- 蜜罐 v2.0 使用 nftset-access 自动禁用机器人
- 支持: 为高级订阅者提供
- 联系: GetPageSpeed Support
NGINX NFTSet Access Module
GetPageSpeed LLC 提供的高级 NGINX 模块
www.getpagespeed.com