This is the solution for the Route 53 DNS Exercise. Each step includes the exact commands, expected output, and troubleshooting guidance.
If the Route 53 console looks a little different when you do this, keep the Route 53 DNS configuration guide and the aws route53 change-resource-record-sets command reference open.
Why This Works
- Alias records let the apex domain point at CloudFront without violating normal DNS rules around CNAMEs at the zone root.
- Route 53 becomes authoritative only after the registrar delegates the domain to its nameservers, which is why nameserver changes matter as much as record creation.
- Verifying with both
digand the browser proves the stack from DNS to TLS to CloudFront is actually working, not just configured on paper.
Confirm the Hosted Zone
aws route53 list-hosted-zones-by-name \
--dns-name example.com \
--output jsonExpected output:
{
"HostedZones": [
{
"Id": "/hostedzone/Z1234567890ABC",
"Name": "example.com.",
"Config": {
"PrivateZone": false
},
"ResourceRecordSetCount": 6
}
]
}Store the hosted zone ID for later use:
HOSTED_ZONE_ID="Z1234567890ABC"Or extract it programmatically:
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones \
--output json \
--query "HostedZones[?Name=='example.com.'].Id | [0]" \
| tr -d '"' | sed 's|/hostedzone/||')
echo "$HOSTED_ZONE_ID"If something went wrong:
- The query returns an empty list: you do not actually have a hosted zone yet. Go back to Hosted Zones and Record Types, create one, and confirm the registrar points at its nameservers before continuing.
- The hosted zone exists but public DNS still fails later: the registrar is still using the wrong nameservers.
Confirming Nameservers (External Registrar Only)
If your domain is registered outside Route 53, confirm the registrar is already using the Route 53 nameservers:
ns-1234.awsdns-56.org
ns-567.awsdns-12.net
ns-890.awsdns-34.co.uk
ns-123.awsdns-78.comUse your actual nameservers from the hosted zone, not these examples. After updating, verify that delegation is working:
dig example.com NS +shortExpected output (after propagation):
ns-1234.awsdns-56.org.
ns-567.awsdns-12.net.
ns-890.awsdns-34.co.uk.
ns-123.awsdns-78.com.If you still see the old nameservers, propagation isn’t complete. This can take up to 48 hours but usually finishes within a few hours.
Create an A Alias Record for the Apex Domain
Get your CloudFront distribution’s domain name if you don’t have it saved:
aws cloudfront get-distribution \
--id E1A2B3C4D5E6F7 \
--output json \
--query "Distribution.DomainName""d111111abcdef8.cloudfront.net"Create the A alias record:
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output json \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}
]
}'Expected output:
{
"ChangeInfo": {
"Id": "/change/C2345678901BCD",
"Status": "PENDING",
"SubmittedAt": "2026-03-18T12:01:00.000Z"
}
}If something went wrong:
InvalidChangeBatch: Alias target name does not lie within the target zone: TheDNSNamein your alias target doesn’t match a valid CloudFront distribution. Double-check the distribution domain name.InvalidChangeBatch: RRSet with DNS name example.com. is not permitted in zone: You’re likely trying to create the record in the wrong hosted zone. Verify that the hosted zone is forexample.com.NoSuchHostedZone: The hosted zone ID is wrong. Runaws route53 list-hosted-zones --output jsonto find the correct ID.
Create an AAAA Alias Record for IPv6
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output json \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "AAAA",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}
]
}'Expected output:
{
"ChangeInfo": {
"Id": "/change/C3456789012CDE",
"Status": "PENDING",
"SubmittedAt": "2026-03-18T12:02:00.000Z"
}
}The output is identical in structure to the A record. The only difference is the "Type": "AAAA" in the request.
Create Records for www
Create both A and AAAA alias records for www.example.com in a single call:
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output json \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "AAAA",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}
]
}'Expected output:
{
"ChangeInfo": {
"Id": "/change/C4567890123DEF",
"Status": "PENDING",
"SubmittedAt": "2026-03-18T12:03:00.000Z"
}
}If something went wrong:
InvalidChangeBatch: Alias target name does not lie within the target zone: Make surewww.example.comis listed as an alternate domain name (CNAME) on your CloudFront distribution. You can check with:The output should include bothaws cloudfront get-distribution-config \ --id E1A2B3C4D5E6F7 \ --output json \ --query "DistributionConfig.Aliases"example.comandwww.example.com. Ifwww.example.comis missing, update the distribution to add it.
Verify DNS Resolution
Wait about 60 seconds, then verify:
dig example.com A +shortExpected output (IP addresses will vary):
13.224.67.18
13.224.67.43
13.224.67.112
13.224.67.84dig example.com AAAA +shortExpected output (IPv6 addresses will vary):
2600:9000:2252:7800:1a:b6c1:4a40:93a1
2600:9000:2252:ae00:1a:b6c1:4a40:93a1
2600:9000:2252:c200:1a:b6c1:4a40:93a1
2600:9000:2252:a400:1a:b6c1:4a40:93a1If you don’t see results, query a Route 53 nameserver directly:
dig example.com A @ns-1234.awsdns-56.org +shortIf the direct query returns results but the general query doesn’t, DNS propagation from your registrar’s nameserver change is still in progress.
For the www subdomain:
dig www.example.com A +shortYou should see the same pattern of CloudFront IP addresses.
Browser Verification
Open https://example.com in a browser. You should see:
- Your frontend content loaded from S3 via CloudFront
- A valid SSL certificate (click the lock icon to verify it was issued by Amazon)
- The URL showing
https://example.com(not the CloudFront domain)
If you created www records, https://www.example.com should show the same content.
List All Records
aws route53 list-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output jsonExpected output:
{
"ResourceRecordSets": [
{
"Name": "example.com.",
"Type": "NS",
"TTL": 172800,
"ResourceRecords": [
{ "Value": "ns-1234.awsdns-56.org." },
{ "Value": "ns-567.awsdns-12.net." },
{ "Value": "ns-890.awsdns-34.co.uk." },
{ "Value": "ns-123.awsdns-78.com." }
]
},
{
"Name": "example.com.",
"Type": "SOA",
"TTL": 900,
"ResourceRecords": [
{ "Value": "ns-1234.awsdns-56.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" }
]
},
{
"Name": "example.com.",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net.",
"EvaluateTargetHealth": false
}
},
{
"Name": "example.com.",
"Type": "AAAA",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net.",
"EvaluateTargetHealth": false
}
},
{
"Name": "www.example.com.",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net.",
"EvaluateTargetHealth": false
}
},
{
"Name": "www.example.com.",
"Type": "AAAA",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net.",
"EvaluateTargetHealth": false
}
}
]
}The key things to confirm:
- NS and SOA records exist for
example.com(auto-created, don’t delete). - A and AAAA alias records exist for
example.com, both pointing to your CloudFront distribution. - A and AAAA alias records exist for
www.example.com(if you created them for the www subdomain). - All alias records show
"HostedZoneId": "Z2FDTNDATAQYW2"and your CloudFront distribution domain name.
Summary
The complete flow, condensed:
# Store your values
HOSTED_ZONE_ID="Z1234567890ABC"
CF_DOMAIN="d111111abcdef8.cloudfront.net"
# Create hosted zone (skip if already exists)
aws route53 create-hosted-zone \
--name example.com \
--caller-reference "example-com-$(date +%s)" \
--region us-east-1 \
--output json
# Create all alias records in one call
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output json \
--change-batch "{
\"Changes\": [
{
\"Action\": \"UPSERT\",
\"ResourceRecordSet\": {
\"Name\": \"example.com\",
\"Type\": \"A\",
\"AliasTarget\": {
\"HostedZoneId\": \"Z2FDTNDATAQYW2\",
\"DNSName\": \"$CF_DOMAIN\",
\"EvaluateTargetHealth\": false
}
}
},
{
\"Action\": \"UPSERT\",
\"ResourceRecordSet\": {
\"Name\": \"example.com\",
\"Type\": \"AAAA\",
\"AliasTarget\": {
\"HostedZoneId\": \"Z2FDTNDATAQYW2\",
\"DNSName\": \"$CF_DOMAIN\",
\"EvaluateTargetHealth\": false
}
}
},
{
\"Action\": \"UPSERT\",
\"ResourceRecordSet\": {
\"Name\": \"www.example.com\",
\"Type\": \"A\",
\"AliasTarget\": {
\"HostedZoneId\": \"Z2FDTNDATAQYW2\",
\"DNSName\": \"$CF_DOMAIN\",
\"EvaluateTargetHealth\": false
}
}
},
{
\"Action\": \"UPSERT\",
\"ResourceRecordSet\": {
\"Name\": \"www.example.com\",
\"Type\": \"AAAA\",
\"AliasTarget\": {
\"HostedZoneId\": \"Z2FDTNDATAQYW2\",
\"DNSName\": \"$CF_DOMAIN\",
\"EvaluateTargetHealth\": false
}
}
}
]
}"
# Verify
dig example.com A +short
dig example.com AAAA +short
dig www.example.com A +shortYou now have DNS fully configured. Your site is reachable at https://example.com and https://www.example.com, served through CloudFront, secured by ACM, with content stored in S3.