Route 53 — DNS, Domain Registration, and Routing Policies Explained
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:
- Browser checks its local cache
- OS resolver checks its cache
- Recursive resolver (ISP or 8.8.8.8) starts the lookup
- Root nameserver says "ask the
.comTLD server" - TLD server says "ask Route 53 nameservers for
example.com" - Route 53 returns the IP address
- 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 Type | Purpose | Example |
|---|---|---|
| A | Maps name to IPv4 address | app.example.com -> 54.23.1.100 |
| AAAA | Maps name to IPv6 address | app.example.com -> 2001:db8::1 |
| CNAME | Maps name to another name | www.example.com -> app.example.com |
| ALIAS | AWS-specific, maps to AWS resources | example.com -> d123.cloudfront.net |
| MX | Mail server routing | Priority 10 -> mail.example.com |
| TXT | Arbitrary text (SPF, DKIM, verification) | "v=spf1 include:_spf.google.com ~all" |
| NS | Nameserver delegation | ns-123.awsdns-45.com |
| SOA | Start 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:
| Feature | CNAME | Alias |
|---|---|---|
| Zone apex support | No | Yes |
| DNS query charge | Standard charges | Free (for AWS resources) |
| Targets | Any hostname | ALB, CloudFront, S3, API Gateway, etc. |
| TTL | You set it | Inherited from target |
| Health check integration | Manual | Automatic 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:
| Scenario | Recommended TTL | Reason |
|---|---|---|
| Static infrastructure | 86400 (24 hours) | Reduces query volume and cost |
| Active-active load balancing | 60 seconds | Quick failover between targets |
| Pre-migration | 300 -> 60 seconds | Lower TTL before the cutover |
| During migration | 60 seconds | Fast rollback if issues arise |
| Post-migration (stable) | 3600+ seconds | Back 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.
