Skip to main content

Route 53 — DNS, Domain Registration, and Routing Policies Explained

· 6 min read
Goel Academy
DevOps & Cloud Learning Hub

Every time someone types your domain name into a browser, a DNS query races across the internet to find the IP address of your server. If DNS is slow, broken, or misconfigured, nothing else matters — your app is invisible. Route 53 is AWS's DNS service, and it does far more than translate names to IPs. It routes traffic intelligently, performs health checks, and can failover to a backup region in seconds.

DNS Fundamentals (Quick Recap)

DNS works like a phone book for the internet. When a user visits app.example.com:

  1. Browser checks its local cache
  2. OS resolver checks its cache
  3. Recursive resolver (ISP or 8.8.8.8) starts the lookup
  4. Root nameserver says "ask the .com TLD server"
  5. TLD server says "ask Route 53 nameservers for example.com"
  6. Route 53 returns the IP address
  7. Browser connects to the IP

This entire dance takes 20-100ms on a cache miss. Route 53 has a global anycast network, meaning DNS queries go to the nearest AWS edge location — there are over 100 worldwide.

Hosted Zones: Public vs Private

A hosted zone is a container for DNS records for a single domain:

# Create a public hosted zone (internet-facing)
aws route53 create-hosted-zone \
--name example.com \
--caller-reference "$(date +%s)" \
--hosted-zone-config Comment="Production domain"

# Create a private hosted zone (VPC-only)
aws route53 create-hosted-zone \
--name internal.example.com \
--caller-reference "$(date +%s)" \
--vpc VPCRegion=us-east-1,VPCId=vpc-abc123 \
--hosted-zone-config Comment="Internal services",PrivateZone=true

Public hosted zones resolve from anywhere on the internet. Private hosted zones only resolve from within associated VPCs — perfect for internal service discovery like db.internal.example.com.

Record Types

Record TypePurposeExample
AMaps name to IPv4 addressapp.example.com -> 54.23.1.100
AAAAMaps name to IPv6 addressapp.example.com -> 2001:db8::1
CNAMEMaps name to another namewww.example.com -> app.example.com
ALIASAWS-specific, maps to AWS resourcesexample.com -> d123.cloudfront.net
MXMail server routingPriority 10 -> mail.example.com
TXTArbitrary text (SPF, DKIM, verification)"v=spf1 include:_spf.google.com ~all"
NSNameserver delegationns-123.awsdns-45.com
SOAStart of Authority (zone metadata)Serial, refresh, retry, expire, TTL

Creating DNS Records

# Create an A record pointing to an EC2 instance
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [{"Value": "54.23.1.100"}]
}
}]
}'

# Create an ALIAS record pointing to a CloudFront distribution
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d123abc.cloudfront.net",
"EvaluateTargetHealth": true
}
}
}]
}'

Alias Records vs CNAME — Know the Difference

This trips up almost everyone. A CNAME cannot be used at the zone apex (example.com), only on subdomains (www.example.com). AWS Alias records solve this:

FeatureCNAMEAlias
Zone apex supportNoYes
DNS query chargeStandard chargesFree (for AWS resources)
TargetsAny hostnameALB, CloudFront, S3, API Gateway, etc.
TTLYou set itInherited from target
Health check integrationManualAutomatic with EvaluateTargetHealth

Rule of thumb: If pointing to an AWS resource, always use Alias. It's free, faster, and works at the apex.

Routing Policies

This is where Route 53 shines. Six routing policies let you control how traffic reaches your infrastructure:

Simple Routing

One record, one or more values. If multiple values, Route 53 returns all and the client picks one randomly:

aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [
{"Value": "54.23.1.100"},
{"Value": "54.23.1.101"}
]
}
}]
}'

Weighted Routing

Split traffic by percentage. Perfect for canary deployments:

# Send 90% to the stable version
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"SetIdentifier": "stable",
"Weight": 90,
"TTL": 60,
"ResourceRecords": [{"Value": "54.23.1.100"}]
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"SetIdentifier": "canary",
"Weight": 10,
"TTL": 60,
"ResourceRecords": [{"Value": "54.23.1.200"}]
}
}]
}'

Latency-Based Routing

Route users to the region with the lowest latency:

# Record for us-east-1
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"SetIdentifier": "us-east-1",
"Region": "us-east-1",
"TTL": 60,
"ResourceRecords": [{"Value": "54.23.1.100"}]
}
}]
}'

Failover Routing

Automatic failover to a secondary when the primary is unhealthy:

# Primary record with health check
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"SetIdentifier": "primary",
"Failover": "PRIMARY",
"TTL": 60,
"ResourceRecords": [{"Value": "54.23.1.100"}],
"HealthCheckId": "health-check-id-123"
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"SetIdentifier": "secondary",
"Failover": "SECONDARY",
"TTL": 60,
"ResourceRecords": [{"Value": "54.23.2.100"}]
}
}]
}'

Health Checks

Health checks are the backbone of intelligent routing. Without them, Route 53 happily sends traffic to dead servers:

# Create an HTTP health check
aws route53 create-health-check \
--caller-reference "$(date +%s)" \
--health-check-config '{
"IPAddress": "54.23.1.100",
"Port": 443,
"Type": "HTTPS",
"ResourcePath": "/health",
"RequestInterval": 10,
"FailureThreshold": 3,
"EnableSNI": true,
"Regions": ["us-east-1", "eu-west-1", "ap-southeast-1"]
}'

Route 53 health checkers run from multiple regions. A resource is marked unhealthy only when the configured threshold of checkers agree it's down — preventing false positives from a single region's network blip.

TTL Strategies

TTL (Time to Live) controls how long resolvers cache your DNS records:

ScenarioRecommended TTLReason
Static infrastructure86400 (24 hours)Reduces query volume and cost
Active-active load balancing60 secondsQuick failover between targets
Pre-migration300 -> 60 secondsLower TTL before the cutover
During migration60 secondsFast rollback if issues arise
Post-migration (stable)3600+ secondsBack to higher TTL for caching

Pro tip: Lower your TTL 24-48 hours before a migration so old cached entries expire. Then make the change. Then raise TTL again once stable.

What's Next?

Your DNS is routing traffic to the right places. But how do you know if your application is actually healthy? Next, we'll dive into CloudWatch — AWS's monitoring service — and learn how to set up alarms, dashboards, and log analysis that catch problems before your users do.


This is Part 11 of our AWS series. DNS feels boring until it breaks — then it's the most exciting 30 minutes of your career.