rdns: NGINX HTTP rDNS 模块
安装
您可以在任何基于 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-rdns
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-rdns
通过在 /etc/nginx/nginx.conf 顶部添加以下内容来启用该模块:
load_module modules/ngx_http_rdns_module.so;
本文档描述了 nginx-module-rdns v1.2.0,于 2026 年 2 月 2 日发布。
NGINX 的反向 DNS 查找模块,具有基于主机名的访问控制。
对客户端 IP 地址执行异步反向 DNS (PTR) 查找,并使用解析的主机名进行访问控制决策、日志记录或条件请求处理。
特性
- 异步 DNS 解析 - 使用 NGINX 的核心解析器进行非阻塞 PTR 查找
- 双重验证模式 - 可选的正向 DNS 验证,以防止 DNS 欺骗
- 基于正则表达式的访问控制 - 根据主机名模式允许或拒绝请求
- 完整上下文支持 - 在
http、server、location和if块中工作 - 高效缓存 - 利用 NGINX 的解析器缓存(最长可达 30 秒或 DNS TTL)
- 动态模块支持 - 可构建为静态或动态模块
- IPv4 和 IPv6 支持 - 适用于两种地址族
快速开始
http {
# 定义一个 DNS 解析器(必需)
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
server {
listen 80;
location / {
# 启用反向 DNS 查找
rdns on;
# 仅允许来自 *.google.com 的请求
rdns_allow \.google\.com$;
# 拒绝来自已知恶意行为者的请求
rdns_deny \.spam\.example\.com$;
# 在您的应用程序中使用主机名
proxy_set_header X-Client-Hostname $rdns_hostname;
proxy_pass http://backend;
}
}
}
指令
rdns
启用或禁用反向 DNS 查找。
| 语法 | rdns on | off | double |
| 默认 | off |
| 上下文 | http、server、location、if |
| 阶段 | rewrite |
值:
| 值 | 描述 |
|---|---|
off |
禁用 rDNS 查找。 $rdns_hostname 将为 - |
on |
执行单个 PTR 查找 |
double |
执行 PTR 查找,然后通过正向 A/AAAA 查找进行验证 |
双重模式 通过验证解析的主机名是否指向原始客户端 IP 地址来防止 DNS 欺骗。如果验证失败,$rdns_hostname 被设置为 not found。
rdns_allow
如果解析的主机名与模式匹配,则允许访问。
| 语法 | rdns_allow regex |
| 默认 | - |
| 上下文 | http、server、location |
| 阶段 | access |
该模式是一个不区分大小写的 PCRE 正则表达式。
rdns_deny
如果解析的主机名与模式匹配,则拒绝访问(返回 403)。
| 语法 | rdns_deny regex |
| 默认 | - |
| 上下文 | http、server、location |
| 阶段 | access |
该模式是一个不区分大小写的 PCRE 正则表达式。
变量
$rdns_hostname
包含反向 DNS 查找的结果。
| 值 | 意义 |
|---|---|
| hostname | 成功解析的主机名 |
not found |
查找失败、超时或双重验证失败 |
- |
在此上下文中禁用 rDNS |
使用示例
验证搜索引擎爬虫
确保声称来自 Googlebot 的请求实际上来自 Google:
location / {
resolver 8.8.8.8;
# 仅对声称为 Googlebot 的请求执行 rDNS
if ($http_user_agent ~* "Googlebot") {
rdns double;
}
# 允许经过验证的 Googlebot
rdns_allow \.googlebot\.com$;
rdns_allow \.google\.com$;
# 您的正常配置
proxy_pass http://backend;
}
按主机名阻止请求
location / {
resolver 8.8.8.8;
rdns on;
# 阻止已知的垃圾邮件来源
rdns_deny \.spam\.example\.com$;
rdns_deny \.malicious\.net$;
proxy_pass http://backend;
}
记录客户端主机名
http {
resolver 8.8.8.8;
log_format with_hostname '$remote_addr - $rdns_hostname - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
server {
access_log /var/log/nginx/access.log with_hostname;
location / {
rdns on;
proxy_pass http://backend;
}
}
}
基于主机名的条件逻辑
location / {
resolver 8.8.8.8;
rdns on;
# 根据主机名设置变量
set $is_internal "no";
if ($rdns_hostname ~ \.internal\.company\.com$) {
set $is_internal "yes";
}
# 在代理头中使用
proxy_set_header X-Is-Internal $is_internal;
proxy_set_header X-Client-Hostname $rdns_hostname;
proxy_pass http://backend;
}
不同位置的不同规则
server {
resolver 8.8.8.8;
# 公共 API - 不使用 rDNS
location /api/public {
proxy_pass http://api-backend;
}
# 管理区域 - 严格的主机名验证
location /admin {
rdns double;
rdns_allow \.admin\.company\.com$;
proxy_pass http://admin-backend;
}
# 一般内容 - 记录主机名
location / {
rdns on;
proxy_pass http://web-backend;
}
}
访问控制行为
规则评估
- 规则按配置中出现的顺序进行评估
- 第一个匹配的规则决定结果:
rdns_allow匹配:请求被允许(继续处理)rdns_deny匹配:请求被拒绝,返回403 Forbidden- 如果没有规则匹配,请求被允许
规则继承
- 子上下文(位置)继承父上下文的规则,仅当它们没有定义自己的规则时
- 一旦子上下文定义了任何
rdns_allow或rdns_deny规则,则不再继承父规则
server {
rdns_allow \.trusted\.com$; # 服务器级别规则
location /public {
# 继承服务器级别的 rdns_allow 规则
}
location /private {
rdns_deny \.untrusted\.com$; # 有自己的规则
# 不继承服务器级别的 rdns_allow
}
}
重要说明
解析器配置
在使用 rdns on 或 rdns double 时,必须在相同上下文或父上下文中定义 resolver 指令。如果未满足此要求,NGINX 将无法启动,并显示错误 no core resolver defined for rdns。
## 正确:定义了解析器
server {
resolver 8.8.8.8;
location / {
rdns on; # 工作正常
}
}
## 错误:没有解析器
server {
location / {
rdns on; # 错误:没有定义核心解析器
}
}
有问题的配置
server { rdns on;
location / {
error_page 404 = @fallback;
}
location @fallback {
# 循环!rDNS 查找重新启动请求处理
}
}
修复后的配置
server { rdns on;
location / {
error_page 404 = @fallback;
}
location @fallback {
rdns off; # 在命名位置禁用 rDNS
# ...
}
} ```
性能考虑
- 每次 rDNS 查找都会增加请求处理的延迟
- 使用条件启用(通过
if块)将查找限制为特定用户代理或条件 - 解析器缓存有助于减少对同一 IP 的重复查找
- 仅在需要防止欺骗时考虑使用
double模式
故障排除
"no core resolver defined for rdns"
在相同或父上下文中添加 resolver 指令:
nginx
resolver 8.8.8.8;
$rdns_hostname 始终为 "not found"
- 验证解析器是否可以从您的服务器访问
- 检查解析器超时设置
- 如果使用
rdns double,确保 PTR 记录的主机名有一个有效的 A/AAAA 记录指向客户端 IP - 检查 NGINX 错误日志以获取解析器错误
$rdns_hostname 始终为 "-"
rdns 指令要么:
- 在当前上下文中未启用
- 设置为 off
- 在条件为假的 if 块中
403 Forbidden 响应
一个 rdns_deny 规则匹配了客户端的主机名。检查您的拒绝模式和实际解析的主机名。
GitHub
您可以在 nginx-module-rdns 的 GitHub 仓库 中找到有关此模块的其他配置提示和文档。