Skip to content

rdns: NGINX HTTP rDNS module

Installation

You can install this module in any RHEL-based distribution, including, but not limited to:

  • RedHat Enterprise Linux 7, 8, 9 and 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 and 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

Enable the module by adding the following at the top of /etc/nginx/nginx.conf:

load_module modules/ngx_http_rdns_module.so;

This document describes nginx-module-rdns v1.2.0 released on Feb 02 2026.


Test Build

Reverse DNS lookup module for NGINX with hostname-based access control.

Perform asynchronous reverse DNS (PTR) lookups on client IP addresses and use the resolved hostname for access control decisions, logging, or conditional request handling.

Features

  • Asynchronous DNS Resolution - Non-blocking PTR lookups using NGINX's core resolver
  • Double Verification Mode - Optional forward DNS verification to prevent DNS spoofing
  • Regex-Based Access Control - Allow or deny requests based on hostname patterns
  • Full Context Support - Works in http, server, location, and if blocks
  • Efficient Caching - Leverages NGINX's resolver cache (up to 30 seconds or DNS TTL)
  • Dynamic Module Support - Build as static or dynamic module
  • IPv4 and IPv6 Support - Works with both address families

Quick Start

http {
    # Define a DNS resolver (required)
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    server {
        listen 80;

        location / {
            # Enable reverse DNS lookup
            rdns on;

            # Allow only requests from *.google.com
            rdns_allow \.google\.com$;

            # Deny requests from known bad actors
            rdns_deny \.spam\.example\.com$;

            # Use the hostname in your application
            proxy_set_header X-Client-Hostname $rdns_hostname;
            proxy_pass http://backend;
        }
    }
}

Directives

rdns

Enables or disables reverse DNS lookups.

Syntax rdns on | off | double
Default off
Context http, server, location, if
Phase rewrite

Values:

Value Description
off Disable rDNS lookup. $rdns_hostname will be -
on Perform a single PTR lookup
double Perform PTR lookup, then verify with forward A/AAAA lookup

Double mode provides protection against DNS spoofing by verifying that the resolved hostname points back to the original client IP address. If verification fails, $rdns_hostname is set to not found.

rdns_allow

Allow access if the resolved hostname matches the pattern.

Syntax rdns_allow regex
Default -
Context http, server, location
Phase access

The pattern is a case-insensitive PCRE regular expression.

rdns_deny

Deny access (return 403) if the resolved hostname matches the pattern.

Syntax rdns_deny regex
Default -
Context http, server, location
Phase access

The pattern is a case-insensitive PCRE regular expression.

Variables

$rdns_hostname

Contains the result of the reverse DNS lookup.

Value Meaning
hostname Successfully resolved hostname
not found Lookup failed, timed out, or double verification failed
- rDNS is disabled in this context

Usage Examples

Verify Search Engine Crawlers

Ensure requests claiming to be from Googlebot actually originate from Google:

location / {
    resolver 8.8.8.8;

    # Only perform rDNS for requests claiming to be Googlebot
    if ($http_user_agent ~* "Googlebot") {
        rdns double;
    }

    # Allow verified Googlebot
    rdns_allow \.googlebot\.com$;
    rdns_allow \.google\.com$;

    # Your normal configuration
    proxy_pass http://backend;
}

Block Requests by Hostname

location / {
    resolver 8.8.8.8;
    rdns on;

    # Block known spam sources
    rdns_deny \.spam\.example\.com$;
    rdns_deny \.malicious\.net$;

    proxy_pass http://backend;
}

Log Client Hostnames

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;
        }
    }
}

Conditional Logic Based on Hostname

location / {
    resolver 8.8.8.8;
    rdns on;

    # Set a variable based on hostname
    set $is_internal "no";
    if ($rdns_hostname ~ \.internal\.company\.com$) {
        set $is_internal "yes";
    }

    # Use in proxy headers
    proxy_set_header X-Is-Internal $is_internal;
    proxy_set_header X-Client-Hostname $rdns_hostname;
    proxy_pass http://backend;
}

Different Rules for Different Locations

server {
    resolver 8.8.8.8;

    # Public API - no rDNS
    location /api/public {
        proxy_pass http://api-backend;
    }

    # Admin area - strict hostname verification
    location /admin {
        rdns double;
        rdns_allow \.admin\.company\.com$;
        proxy_pass http://admin-backend;
    }

    # General content - log hostnames
    location / {
        rdns on;
        proxy_pass http://web-backend;
    }
}

Access Control Behavior

Rule Evaluation

  1. Rules are evaluated in the order they appear in the configuration
  2. The first matching rule determines the outcome:
  3. rdns_allow match: Request is allowed (processing continues)
  4. rdns_deny match: Request is denied with 403 Forbidden
  5. If no rules match, the request is allowed

Rule Inheritance

  • Child contexts (locations) inherit rules from parent contexts only if they don't define their own rules
  • Once a child defines any rdns_allow or rdns_deny rule, parent rules are not inherited
server {
    rdns_allow \.trusted\.com$;  # Server-level rule

    location /public {
        # Inherits server-level rdns_allow rule
    }

    location /private {
        rdns_deny \.untrusted\.com$;  # Has own rule
        # Does NOT inherit server-level rdns_allow
    }
}

Important Notes

Resolver Configuration

A resolver directive must be defined in the same context or a parent context when using rdns on or rdns double. NGINX will fail to start with the error no core resolver defined for rdns if this requirement is not met.

# Good: resolver defined
server {
    resolver 8.8.8.8;
    location / {
        rdns on;  # Works
    }
}

# Bad: no resolver
server {
    location / {
        rdns on;  # Error: no core resolver defined
    }
}

Problematic configuration

server { rdns on;

location / {
    error_page 404 = @fallback;
}

location @fallback {
    # Loop! The rDNS lookup restarts request processing
}

}

Fixed configuration

server { rdns on;

location / {
    error_page 404 = @fallback;
}

location @fallback {
    rdns off;  # Disable rDNS in named location
    # ...
}

} ```

Performance Considerations

  • Each rDNS lookup adds latency to request processing
  • Use conditional enabling (via if blocks) to limit lookups to specific user agents or conditions
  • The resolver cache helps reduce repeated lookups for the same IP
  • Consider double mode only when spoofing protection is necessary

Troubleshooting

"no core resolver defined for rdns"

Add a resolver directive in the same or parent context: nginx resolver 8.8.8.8;

$rdns_hostname is always "not found"

  1. Verify the resolver is reachable from your server
  2. Check resolver timeout settings
  3. If using rdns double, ensure the PTR record's hostname has a valid A/AAAA record pointing back to the client IP
  4. Check NGINX error logs for resolver errors

$rdns_hostname is always "-"

The rdns directive is either: - Not enabled in the current context - Set to off - Inside an if block whose condition is false

403 Forbidden responses

An rdns_deny rule matched the client's hostname. Check your deny patterns and the actual hostname being resolved.

GitHub

You may find additional configuration tips and documentation for this module in the GitHub repository for nginx-module-rdns.