Setting Up Reverse DNS (PTR Records) Correctly

A complete guide to setting up PTR records for email deliverability, including cloud provider configuration for AWS, GCP, and Azure, and verifying FCrDNS.

What Is Reverse DNS and Why Does It Matter?

Forward DNS resolves a hostname to an IP address (dig mail.yourdomain.com). Reverse DNS (rDNS) does the opposite: resolving an IP address to a hostname (dig -x 203.0.113.10). The DNS records used for reverse lookups are called PTR records, and they live in the special in-addr.arpa domain.

Reverse DNS matters because:

  • Email deliverability: Receiving mail servers check PTR records as part of spam filtering. An IP without a PTR record is a strong spam signal.
  • Server identification: Logs, monitoring tools, and security audits are far more readable with hostnames than raw IPs.
  • Network troubleshooting: traceroute output is more useful with hostnames than IP addresses.
  • ISP abuse handling: ISPs use PTR records to identify responsible parties when an IP is involved in abuse reports.

Requesting PTR from Your ISP

Unlike forward DNS records (which you control in your domain registrar), PTR records for IP addresses are managed by whoever owns the IP address block — usually your ISP. You cannot create PTR records for your IP without their cooperation.

The process:

  1. Identify your IP's owner: Use whois to find the organization bash whois 203.0.113.10 # Look for: OrgAbuseEmail, OrgTechEmail, or RIPE/ARIN contact

  2. Contact the ISP's NOC or technical support with:

  3. Your IP address
  4. The desired PTR hostname (e.g., mail.yourdomain.com)
  5. Proof of ownership of the hostname

  6. Wait for propagation — ISPs typically process PTR requests within 24-48 hours

For residential ISPs, PTR requests are often unavailable or limited to a single generic hostname. Business fiber and colocation providers handle PTR changes routinely.

Cloud Provider rDNS

Cloud providers own their IP blocks and provide self-service PTR configuration.

AWS

# AWS: request PTR record for Elastic IP
# Via Console:
# EC2 → Elastic IPs → Select IP → Actions → Edit reverse DNS

# Via CLI (AWS supports PTR for Elastic IPs only)
aws ec2 describe-addresses --filters "Name=public-ip,Values=203.0.113.10"

# Submit reverse DNS request
# Note: AWS calls this "Request PTR record" in the console
# The hostname must forward-resolve to the same IP (FCrDNS required)
aws ec2 modify-address-attribute \
  --allocation-id eipalloc-0123456789abcdef0 \
  --domain-name mail.yourdomain.com \
  --region us-east-1

GCP (Google Cloud Platform)

# GCP: set PTR in VM settings
gcloud compute instances describe INSTANCE_NAME \
  --format="get(networkInterfaces)"

# Set custom hostname (used for PTR)
gcloud compute instances edit INSTANCE_NAME \
  --update-metadata "hostname=mail.yourdomain.com"

# Or via Console:
# Compute Engine → VM instances → Edit → Custom hostname
# Fill in: mail.yourdomain.com

Azure

# Azure: set PTR via reverse FQDN in public IP settings
az network public-ip update \
  --resource-group myResourceGroup \
  --name myPublicIP \
  --reverse-fqdn mail.yourdomain.com.

# Verify
az network public-ip show \
  --resource-group myResourceGroup \
  --name myPublicIP \
  --query "reverseFqdn"

DigitalOcean, Linode, Vultr, Hetzner

These providers allow PTR configuration directly in their web control panels:

Provider Location
DigitalOcean Networking → Floating IPs or Droplet → Networking → Edit reverse DNS
Linode Linodes → Select → Network → IP Addresses → Edit rDNS
Vultr My IP Address → Edit → Reverse DNS
Hetzner Server → IPs → Set rDNS

Verifying with dig -x

After the PTR record is configured, verify it with dig:

# Reverse lookup using dig
dig -x 203.0.113.10

# Shorter output (just the result)
dig +short -x 203.0.113.10
# Should return: mail.yourdomain.com.

# Alternative: host command
host 203.0.113.10
# 10.113.0.203.in-addr.arpa domain name pointer mail.yourdomain.com.

# nslookup
nslookup 203.0.113.10

# Check using different resolvers to confirm propagation
dig +short -x 203.0.113.10 @8.8.8.8
dig +short -x 203.0.113.10 @1.1.1.1
dig +short -x 203.0.113.10 @9.9.9.9

The PTR record should resolve to a fully qualified domain name ending with a period (.). This is normal DNS notation for an absolute name.

FCrDNS Check

FCrDNS (Forward-Confirmed Reverse DNS) means the PTR hostname forward-resolves back to the original IP. Email servers specifically check for this:

# Step 1: Get PTR record
PTR=$(dig +short -x 203.0.113.10)
echo "PTR: $PTR"
# PTR: mail.yourdomain.com.

# Step 2: Forward-resolve the PTR hostname
dig +short $PTR
# Should return: 203.0.113.10

# One-liner FCrDNS check
IP="203.0.113.10"
HOSTNAME=$(dig +short -x $IP | sed 's/\.$//')
RESOLVED=$(dig +short $HOSTNAME)
if [ "$RESOLVED" = "$IP" ]; then
    echo "FCrDNS PASS: $IP <-> $HOSTNAME"
else
    echo "FCrDNS FAIL: $IP -> $HOSTNAME -> $RESOLVED (mismatch)"
fi

FCrDNS failure reasons:

Failure Cause Fix
PTR exists, no A record Forward DNS not configured Add A record for PTR hostname
PTR points to wrong hostname Different domain than sending domain Align PTR with MAIL FROM domain
Forward resolves to different IP IP change, stale record Update A record
CNAME in forward lookup Some MTAs reject CNAMEs Use A record directly

Impact on Email Deliverability

PTR records directly affect email deliverability through several mechanisms:

  1. MTA validation: Most receiving MTAs (Postfix, Exim, Exchange) log a warning or reject mail from IPs without PTR records
  2. Spam scoring: SpamAssassin adds points for missing PTR
  3. Blacklisting: SORBS and other blacklists maintain lists of IPs without PTR records
  4. Google/Microsoft: Both run automated checks; missing PTR reduces inbox placement
# Test your PTR impact on email scoring
# Send a test email to [email protected]
# You'll receive a full authentication report

# Or use MXToolbox
# https://mxtoolbox.com/ReverseLookup.aspx

# Complete email configuration check
curl -s "https://api.mxtoolbox.com/api/v1/Lookup/rdns/?argument=203.0.113.10"

IPv6 rDNS

IPv6 PTR records use the ip6.arpa domain and require reversing all 32 nibbles of the full IPv6 address.

# Example IPv6 address: 2001:db8::1
# Full form: 2001:0db8:0000:0000:0000:0000:0000:0001
# Reversed nibbles: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa

# dig handles this automatically
dig -x 2001:db8::1

# Python helper to compute ip6.arpa zone
python3 -c "
import ipaddress
ip = ipaddress.ip_address('2001:db8::1')
expanded = ip.exploded.replace(':', '')
arpa = '.'.join(reversed(expanded)) + '.ip6.arpa'
print(arpa)
"
# Output: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa

For cloud providers with IPv6, PTR configuration follows the same UI paths as IPv4. For self-managed IPv6 delegations, your ISP must delegate the reverse zone (e.g., /64 of your prefix) to your nameservers, after which you manage PTR records yourself.

; /64 reverse zone example in BIND
$ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
$TTL 300
@   IN SOA  ns1.yourdomain.com. admin.yourdomain.com. (
               2024010101 ; serial
               3600       ; refresh
               900        ; retry
               604800     ; expire
               300 )      ; minimum
    IN NS   ns1.yourdomain.com.
    IN NS   ns2.yourdomain.com.

; Individual PTR records
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0  IN PTR mail.yourdomain.com.
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0  IN PTR web.yourdomain.com.