Skip to main content

NGINX / Security

NGINX Reverse DNS Module: Hostname-Based Access Control

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

When a client connects to your NGINX server, you see an IP address. However, IP addresses tell you nothing about who owns them. A request claiming to be from Googlebot might actually come from a scraper. Traffic from a “trusted partner” could originate from a compromised server. The NGINX reverse DNS module solves this problem by resolving client IP addresses to hostnames, enabling hostname-based access control decisions.

The nginx-module-rdns package is available exclusively from the GetPageSpeed NGINX Extras repository. This remarkable NGINX reverse DNS module is a complete clean-room implementation and drop-in replacement for the original open source ngx_http_rdns module, which was abandoned years ago and no longer compiles with modern NGINX versions. Our implementation brings this essential functionality back to life with full compatibility for the latest NGINX releases, including dynamic module support.

What Is Reverse DNS and Why Does It Matter?

Reverse DNS (rDNS) is the process of resolving an IP address back to a hostname. While forward DNS maps example.com to 93.184.216.34, reverse DNS maps 93.184.216.34 back to a hostname like server1.example.com.

For system administrators, reverse DNS verification serves several critical security purposes:

  • Crawler verification: Confirm that requests claiming to be from search engines actually originate from their networks
  • Partner authentication: Verify that traffic comes from legitimate partner hostnames
  • Threat identification: Log and analyze the hostnames of suspicious traffic sources
  • Access control: Allow or deny requests based on hostname patterns instead of maintaining IP lists

The challenge with IP-based access control is that IP addresses change frequently. Cloud providers reassign IPs, companies change hosting providers, and maintaining accurate IP allowlists becomes an ongoing burden. Hostname-based verification offers a more stable alternative because organizations control their DNS records.

How the NGINX rDNS Module Works

The NGINX reverse DNS module (ngx_http_rdns) performs asynchronous reverse DNS lookups during request processing. Here is how it operates:

  1. Client connects: A request arrives from IP address 66.249.66.1
  2. PTR lookup: The module queries DNS for the PTR record of 1.66.249.66.in-addr.arpa
  3. Hostname resolved: DNS returns crawl-66-249-66-1.googlebot.com
  4. Access decision: Your configuration rules match against this hostname

The module integrates with NGINX’s core resolver, which means lookups are non-blocking. Your server continues processing other requests while waiting for DNS responses.

Single vs Double Verification Mode

The module offers two verification modes:

Single mode (rdns on) performs only the PTR lookup. This is faster but vulnerable to DNS spoofing. An attacker controlling their PTR records could set them to claim any hostname.

Double mode (rdns double) adds forward verification. After resolving the PTR record to a hostname, the module performs an A or AAAA lookup on that hostname. Only if the forward lookup returns the original client IP does verification succeed.

For security-critical applications, always use double mode. The additional DNS query adds minimal latency but provides strong spoofing protection.

Installation on RHEL, CentOS, Rocky Linux, and AlmaLinux

The NGINX reverse DNS module is exclusively available through the GetPageSpeed NGINX Extras repository, which provides pre-built packages for all Enterprise Linux distributions. This is the only source for a maintained, modern build of this module.

Enable the GetPageSpeed Repository

First, install the repository configuration:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm

Install the Module

Install the rDNS module package:

sudo dnf install nginx-module-rdns

This installs the compiled module to /usr/lib64/nginx/modules/.

Load the Module

Add the following line to your /etc/nginx/nginx.conf at the top, before any http block:

load_module modules/ngx_http_rdns_module.so;

Verify the configuration and reload NGINX:

sudo nginx -t && sudo systemctl reload nginx

Drop-In Replacement for the Abandoned Original

If you previously used the original ngx_http_rdns module before it was abandoned, you’ll find our NGINX reverse DNS module is a complete drop-in replacement. All existing configurations work without modification:

  • Same directive names: rdns, rdns_allow, rdns_deny
  • Same variable: $rdns_hostname
  • Same contexts: http, server, location, if
  • Same behavior and semantics

Simply install from the GetPageSpeed repository and your existing configurations will work immediately. No migration needed.

Configuration Reference

The module provides three directives and one variable.

The rdns Directive

The rdns directive enables or disables reverse DNS lookups.

Property Value
Syntax rdns on | off | double
Default off
Context http, server, location, if

Values explained:

  • off: Disable rDNS lookup. The $rdns_hostname variable contains -
  • on: Perform a single PTR lookup
  • double: Perform PTR lookup followed by forward A/AAAA verification

The rdns_allow Directive

The rdns_allow directive permits access when the resolved hostname matches a pattern.

Property Value
Syntax rdns_allow regex
Default none
Context http, server, location

The pattern is a case-insensitive PCRE regular expression. Use proper escaping for literal dots.

The rdns_deny Directive

The rdns_deny directive blocks access (returns 403 Forbidden) when the hostname matches.

Property Value
Syntax rdns_deny regex
Default none
Context http, server, location

The $rdns_hostname Variable

This variable contains the result of the reverse DNS lookup:

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

Practical Configuration Examples

Verifying Search Engine Crawlers

One of the most valuable uses of the NGINX reverse DNS module is verifying legitimate search engine crawlers. Many bots falsely identify as Googlebot to bypass rate limiting or access restricted content. Google officially recommends using reverse DNS verification to confirm Googlebot identity.

http {
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    server {
        listen 80;
        server_name example.com;

        location / {
            # Only verify requests claiming to be Googlebot
            if ($http_user_agent ~* "Googlebot") {
                rdns double;
            }

            # Allow verified Google crawlers
            rdns_allow \.googlebot\.com$;
            rdns_allow \.google\.com$;

            proxy_pass http://backend;
        }
    }
}

This configuration performs rDNS verification only when the User-Agent contains “Googlebot”. Legitimate Google crawlers resolve to hostnames ending in .googlebot.com or .google.com. The double mode ensures spoofed PTR records are rejected.

Blocking Malicious Hostnames

You can block requests from known malicious hostname patterns:

http {
    resolver 8.8.8.8 valid=300s;

    server {
        listen 80;
        server_name example.com;

        location /api {
            rdns on;

            # Block known bad actors
            rdns_deny \.spam\.example\.net$;
            rdns_deny \.malware-host\.com$;
            rdns_deny ^crawler\d+\.aggressive-bot\.org$;

            proxy_pass http://api-backend;
        }
    }
}

Logging Client Hostnames

Even without access control rules, logging resolved hostnames provides valuable security intelligence:

http {
    resolver 8.8.8.8 valid=300s;

    log_format detailed '$remote_addr - $rdns_hostname [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';

    server {
        listen 80;
        server_name example.com;

        access_log /var/log/nginx/access.log detailed;

        location / {
            rdns on;
            proxy_pass http://backend;
        }
    }
}

Your logs now include hostnames like crawl-66-249-66-1.googlebot.com instead of just IP addresses, making log analysis more informative.

Restricting Admin Access by Hostname

Protect administrative areas by requiring connections from specific hostnames. For additional protection, consider combining this with NGINX basic authentication:

server {
    resolver 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    location /admin {
        rdns double;

        # Only allow from company network hostnames
        rdns_allow \.internal\.company\.com$;
        rdns_allow ^vpn-\d+\.company\.com$;

        proxy_pass http://admin-backend;
    }

    location / {
        # Public access, no rDNS needed
        proxy_pass http://public-backend;
    }
}

Passing Hostname to Backend Applications

Forward the resolved hostname to your application for additional processing:

location / {
    resolver 8.8.8.8 valid=300s;
    rdns on;

    proxy_set_header X-Client-Hostname $rdns_hostname;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://backend;
}

Your application can then implement its own hostname-based logic using the X-Client-Hostname header.

Understanding Rule Evaluation

The module evaluates rdns_allow and rdns_deny rules in the order they appear in your configuration. The first matching rule determines the outcome:

  1. If rdns_allow matches first, the request proceeds
  2. If rdns_deny matches first, NGINX returns 403 Forbidden
  3. If no rules match, the request proceeds

This means rule order matters:

# This configuration allows .google.com but denies everything else
location /api {
    rdns double;
    rdns_allow \.google\.com$;
    rdns_deny .*;  # Deny all other hostnames
}

Rule Inheritance Behavior

Rules inherit from parent contexts only when child contexts define no rules:

server {
    rdns_allow \.trusted\.com$;  # Server-level rule

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

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

Performance Considerations

Reverse DNS lookups add latency to request processing. Consider these factors when deploying the NGINX reverse DNS module:

DNS Query Latency

Each rDNS lookup requires at least one DNS query. In double mode, two queries are needed. Query times typically range from 1-50ms depending on your resolver distance and DNS server performance.

Mitigation strategies:

  • Use fast, local DNS resolvers
  • Configure appropriate resolver_timeout values
  • Enable rDNS only for specific locations or conditions

Resolver Caching

NGINX caches DNS responses according to the valid parameter in your resolver directive:

resolver 8.8.8.8 valid=300s;

This caches responses for 300 seconds, reducing repeated lookups for the same IP addresses. However, this also means hostname changes take time to propagate.

Conditional Enabling

Avoid performing rDNS on every request. Use conditions to limit lookups:

# Only verify suspicious user agents
if ($http_user_agent ~* "(bot|crawler|spider)") {
    rdns double;
}

High-Traffic Considerations

On high-traffic servers, DNS query volume can become significant. Ensure your DNS resolver infrastructure can handle the load, or consider implementing rDNS verification at a rate-limited layer before NGINX. For comprehensive traffic management, see our guide on NGINX rate limiting.

Troubleshooting Common Issues

Error: “no core resolver defined for rdns”

This error occurs when you enable rdns on or rdns double without defining a resolver:

# Wrong: no resolver defined
server {
    location / {
        rdns on;  # Error!
    }
}

# Correct: resolver defined in same or parent context
server {
    resolver 8.8.8.8;
    location / {
        rdns on;  # Works
    }
}

Variable $rdns_hostname Always Shows “not found”

Several conditions cause “not found” results:

  1. No PTR record exists: The client IP has no reverse DNS entry
  2. DNS timeout: The resolver didn’t respond within resolver_timeout
  3. Double verification failed: PTR resolved but forward lookup didn’t match the original IP
  4. Resolver unreachable: Your NGINX server cannot reach the configured DNS resolver

Check NGINX error logs for resolver-related messages:

tail -f /var/log/nginx/error.log | grep -i resolver

Variable $rdns_hostname Always Shows “-“

The dash indicates rDNS is disabled. Verify that:

  1. The rdns directive is set to on or double
  2. The directive is in the correct context (location, server, or http)
  3. Any if conditions containing the rdns directive evaluate to true

Redirect Loops with Named Locations

Enabling rDNS globally can cause issues with named locations:

# Problematic: causes redirect loops
server {
    rdns on;

    location / {
        error_page 404 = @fallback;
    }

    location @fallback {
        # rDNS restarts request processing, causing loop
    }
}

# Fixed: disable rDNS in named location
server {
    rdns on;

    location / {
        error_page 404 = @fallback;
    }

    location @fallback {
        rdns off;  # Prevents loop
        # handle fallback
    }
}

Security Best Practices

Follow these recommendations for secure rDNS deployment:

Always Use Double Mode for Access Control

Single mode PTR lookups are trivially spoofable. Any attacker controlling their IP’s reverse DNS can claim any hostname. Always use rdns double when making access control decisions:

# Insecure: single mode is spoofable
rdns on;
rdns_allow \.trusted\.com$;

# Secure: double mode verifies forward DNS
rdns double;
rdns_allow \.trusted\.com$;

Combine with Other Security Measures

Reverse DNS verification works best as part of defense in depth. Consider combining it with TLS hardening and other security layers:

location /api {
    # Layer 1: Rate limiting
    limit_req zone=api burst=10;

    # Layer 2: rDNS verification
    rdns double;
    rdns_allow \.partner\.com$;

    # Layer 3: API key validation in backend
    proxy_pass http://api-backend;
}

Monitor DNS Resolution Failures

High rates of “not found” results may indicate:

  • Attackers probing your server from IPs without rDNS
  • DNS infrastructure issues
  • Legitimate clients without rDNS (some are valid)

Log and alert on unusual patterns:

log_format rdns_failures '$remote_addr - $rdns_hostname - $request';

map $rdns_hostname $loggable {
    "not found" 1;
    default 0;
}

access_log /var/log/nginx/rdns_failures.log rdns_failures if=$loggable;

Verify Crawler Patterns Regularly

Search engines occasionally change their crawler hostnames. Verify your allow patterns remain accurate:

  • Google: *.googlebot.com, *.google.com
  • Bing: *.search.msn.com
  • Yandex: *.yandex.com, *.yandex.ru, *.yandex.net

Consult each search engine’s official documentation for current crawler verification guidance.

Testing Your Configuration

After configuring the module, verify it works correctly.

Check Configuration Syntax

sudo nginx -t

Test from Known Hostnames

If you have access to a server with known rDNS, make requests from it:

curl -H "Host: example.com" http://your-server/

Verify Variable Values

Create a test location that returns the resolved hostname:

location /rdns-test {
    resolver 8.8.8.8 valid=60s;
    rdns on;
    return 200 "Your hostname: $rdns_hostname\n";
    add_header Content-Type text/plain;
}

Access this endpoint to see what hostname your IP resolves to:

curl http://example.com/rdns-test

Simulate Crawler Verification

Test your crawler verification logic by checking against known Googlebot IPs. Google publishes its crawler IP ranges, allowing you to verify your configuration catches legitimate crawlers.

Conclusion

The NGINX reverse DNS module is an exceptional tool for hostname-based access control. By verifying client hostnames through DNS lookups, you can authenticate legitimate crawlers, restrict access to trusted partners, and gain deeper visibility into who accesses your server.

This module is exclusively available from the GetPageSpeed NGINX Extras repository — the only source for a modern, maintained build that works with current NGINX versions. As a complete drop-in replacement for the abandoned original open source module, it breathes new life into this essential security functionality.

Key takeaways:

  • Use double mode for any security-critical access control
  • Conditional enabling prevents unnecessary DNS queries
  • Combine with other security measures for defense in depth
  • Monitor resolution failures to detect issues and attacks
  • Available exclusively from GetPageSpeed — install with dnf install nginx-module-rdns

Get started today by enabling the GetPageSpeed repository and installing the NGINX reverse DNS module.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.