Introduction

Reverse DNS (rDNS) maps IP addresses back to domain names using PTR records. While forward DNS (domain to IP) is managed by domain owners, reverse DNS is controlled by the IP address owner - typically your ISP, cloud provider, or hosting company. When reverse DNS fails or returns unexpected results, email servers reject your messages, SSH connections show warnings, and security tools flag your server as suspicious.

Symptoms

  • Email rejected by receiving servers with "no reverse DNS" or "PTR lookup failed"
  • Email marked as spam due to missing or mismatched PTR
  • SSH warning: "reverse DNS lookup for IP failed"
  • Server blocked by RBL (Real-time Block Lists)
  • Security scanners flag server as suspicious
  • Mail server logs show connection rejections from destination servers
  • HELO/EHLO hostname mismatch warnings in mail logs

Common Causes

  • No PTR record exists for the IP address
  • PTR record points to wrong hostname
  • Forward DNS (A record) and reverse DNS (PTR) don't match
  • PTR record managed by ISP/hosting provider, not updated
  • Multiple PTR records for single IP (ambiguous)
  • IP address recently changed without PTR update
  • Cloud/VPS provider requires specific setup for PTR

Step-by-Step Fix

  1. 1.Check current reverse DNS for your IP address.

```bash # Get your public IP curl -s ifconfig.me # Or curl -s ipinfo.io/ip

# Check reverse DNS using dig dig -x 192.0.2.10 +short

# Using host command host 192.0.2.10

# Using nslookup nslookup 192.0.2.10

# Expected output: hostname that resolves back to this IP # mail.example.com

# If empty or "NXDOMAIN", no PTR record exists ```

  1. 1.Verify forward and reverse DNS match bidirectionally.

```bash # Check reverse DNS IP="192.0.2.10" ptr_hostname=$(dig -x $IP +short) echo "Reverse DNS (PTR): $ptr_hostname"

# Check forward DNS for that hostname forward_ip=$(dig ${ptr_hostname%.} A +short) echo "Forward DNS (A): $forward_ip"

# They should match! if [ "$IP" = "$forward_ip" ]; then echo "OK: Forward and reverse DNS match" else echo "ERROR: Mismatch detected" echo " IP: $IP" echo " PTR points to: $ptr_hostname" echo " That hostname resolves to: $forward_ip" fi ```

  1. 1.Identify who controls the PTR record for your IP.

```bash # PTR records are managed by the IP block owner # Find who controls your IP's reverse DNS zone

# Get your IP and network info IP="192.0.2.10"

# Use WHOIS to find the network owner whois $IP | grep -E "(OrgName|Organization|NetName|NetRange)"

# For AWS: # Look for "Amazon" in OrgName # PTR is managed via EC2 console or Elastic IP settings

# For Google Cloud: # Look for "Google" in OrgName # PTR configured via Cloud DNS for the VPC

# For Azure: # Look for "Microsoft" in OrgName # PTR configured via Azure DNS reverse lookup zone

# For other providers: # Check provider's control panel or contact support ```

  1. 1.Request or configure PTR record with your provider.

```bash # AWS EC2 Elastic IP: # 1. Go to EC2 Console -> Elastic IPs # 2. Select IP -> Actions -> Update reverse DNS # 3. Enter hostname (must have matching A record) # 4. Verify with dig -x after update

# Google Cloud: # 1. Create Cloud DNS managed reverse zone # 2. Add PTR record for IP # 3. Enable Cloud DNS for the VPC

# Azure: # 1. Create reverse DNS lookup zone (ARPA zone) # 2. Add PTR record # 3. Register with Azure support for delegation

# Traditional hosting/ISP: # Contact support with: # - IP address # - Desired hostname # - Confirm A record exists

# Example request: # "Please set reverse DNS for IP 192.0.2.10 to mail.example.com" # "I confirm mail.example.com resolves to 192.0.2.10" ```

  1. 1.Ensure the forward A record exists before setting PTR.

```bash # CRITICAL: PTR hostname must have matching A record

# Check A record exists dig mail.example.com A +short

# Must return your IP # 192.0.2.10

# If empty, add A record first: # In your DNS zone: mail.example.com. 3600 IN A 192.0.2.10

# Wait for propagation, then request PTR update

# Verify both directions: hostname="mail.example.com" ip="192.0.2.10"

echo "Forward: $hostname -> $(dig $hostname A +short)" echo "Reverse: $ip -> $(dig -x $ip +short)" ```

  1. 1.Verify mail server HELO matches PTR hostname.

```bash # Check mail server's HELO announcement

# Connect to mail server telnet 192.0.2.10 25

# Look for server greeting: # 220 mail.example.com ESMTP Postfix

# The hostname after "220" is the HELO name

# Check Postfix config: postconf | grep myhostname # Should return: myhostname = mail.example.com

# In /etc/postfix/main.cf: # myhostname = mail.example.com

# For other mail servers: # Exim: primary_hostname = mail.example.com # Sendmail: define(confDOMAIN_NAME', mail.example.com') ```

  1. 1.Check for multiple PTR records (problematic).

```bash # Multiple PTR records for one IP causes ambiguity # Some systems may pick randomly, causing inconsistent behavior

# Check for multiple PTRs dig -x 192.0.2.10

# If ANSWER SECTION shows multiple PTR records: # 10.2.0.192.in-addr.arpa. 3600 IN PTR mail.example.com. # 10.2.0.192.in-addr.arpa. 3600 IN PTR www.example.com. # This is problematic!

# Contact provider to remove extra PTR records # Keep only one PTR per IP ```

  1. 1.Test PTR from multiple DNS servers.

```bash # Verify PTR is visible globally for resolver in 8.8.8.8 1.1.1.1 9.9.9.9; do echo "Resolver $resolver:" dig -x 192.0.2.10 @$resolver +short done

# All should return the same hostname # If some return empty, propagation may be incomplete

# Check authoritative reverse DNS server # Find it using SOA for reverse zone dig 10.2.0.192.in-addr.arpa SOA +short

# Query that server directly dig -x 192.0.2.10 @<nameserver-from-soa> ```

  1. 1.Validate email delivery after PTR fix.

```bash # Send test email and check headers # Look for Received-SPF and Authentication-Results

# Use mail tester tools: # - https://mail-tester.com # - https://mxtoolbox.com/deliverability

# Manual SMTP test: # Connect from your mail server telnet recipient-domain.com 25

# Watch for rejection messages in SMTP session # Common rejection if PTR missing: # "550 5.7.1 Client host rejected: cannot find your hostname"

# Check your mail logs tail -f /var/log/mail.log | grep -i "ptr|reverse|hostname"

# Postfix: postfix check postconf | grep hostname

# Look for messages like: # "warning: hostname xxx does not resolve to address xxx" ```

  1. 1.Monitor PTR status and set up alerts.

```bash # Create monitoring script #!/bin/bash

IP="192.0.2.10" EXPECTED_PTR="mail.example.com"

# Check reverse DNS ptr=$(dig -x $IP +short) if [ -z "$ptr" ]; then echo "ERROR: No PTR record for $IP" # Send alert elif [ "$ptr" != "$EXPECTED_PTR." ]; then echo "WARNING: PTR mismatch for $IP" echo "Expected: $EXPECTED_PTR" echo "Got: $ptr" # Send alert else echo "OK: PTR correct for $IP" fi

# Check forward DNS matches forward=$(dig ${ptr%.} A +short) if [[ ! "$forward" =~ "$IP" ]]; then echo "ERROR: Forward/reverse mismatch" fi ```

Verification

Complete reverse DNS verification:

```bash # 1. Check PTR exists IP="192.0.2.10" echo "=== Reverse DNS Check ===" ptr=$(dig -x $IP +short) echo "PTR for $IP: $ptr"

# 2. Check forward DNS echo -e "\n=== Forward DNS Check ===" if [ -n "$ptr" ]; then hostname=${ptr%.} forward=$(dig $hostname A +short) echo "$hostname resolves to: $forward" fi

# 3. Verify bidirectional match echo -e "\n=== Bidirectional Match ===" if [ "$forward" = "$IP" ]; then echo "OK: Forward and reverse match" else echo "FAIL: Forward/reverse mismatch" fi

# 4. Check HELO matches echo -e "\n=== Mail Server HELO ===" echo "QUIT" | nc $IP 25 2>/dev/null | head -1

# 5. Test from multiple resolvers echo -e "\n=== Global Propagation ===" for resolver in 8.8.8.8 1.1.1.1; do echo -n "$resolver: " dig -x $IP @$resolver +short done

# 6. Check not in RBL echo -e "\n=== RBL Check ===" # Check common blocklists for rbl in zen.spamhaus.org bl.spamcop.net; do reversed=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}') if dig ${reversed}.${rbl} A +short | grep -q .; then echo "LISTED on $rbl" else echo "OK on $rbl" fi done ```

Provider-Specific PTR Instructions

```bash # AWS EC2 # - Elastic IP required for custom PTR # - Console -> EC2 -> Elastic IPs -> Actions -> Update reverse DNS

# Google Cloud # - Compute Engine -> VM instances -> click VM -> Edit # - Public DNS PTR record must be configured in Cloud DNS

# Azure # - Create reverse DNS zone (PTR zone type) # - Contact Azure support for delegation

# DigitalOcean # - Control Panel -> Networking -> Domains # - Not all IPs support custom PTR (contact support)

# Vultr # - Server Settings -> Reverse DNS # - Enter hostname (must have A record)

# Linode # - Linodes -> Remote Access -> Reverse DNS # - Must be within Linode's IP range

# Self-managed/ISP # - Contact support with IP and desired hostname ```

A correct PTR record is essential for email deliverability and server reputation. Always verify bidirectional resolution after any changes.