Steve Kinney

Solution: Configure DNS for Your Site

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 dig and 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 json

Expected 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.com

Use your actual nameservers from the hosted zone, not these examples. After updating, verify that delegation is working:

dig example.com NS +short

Expected 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: The DNSName in 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 for example.com.
  • NoSuchHostedZone: The hosted zone ID is wrong. Run aws route53 list-hosted-zones --output json to 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 sure www.example.com is listed as an alternate domain name (CNAME) on your CloudFront distribution. You can check with:
    aws cloudfront get-distribution-config \
      --id E1A2B3C4D5E6F7 \
      --output json \
      --query "DistributionConfig.Aliases"
    The output should include both example.com and www.example.com. If www.example.com is missing, update the distribution to add it.

Verify DNS Resolution

Wait about 60 seconds, then verify:

dig example.com A +short

Expected output (IP addresses will vary):

13.224.67.18
13.224.67.43
13.224.67.112
13.224.67.84
dig example.com AAAA +short

Expected 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:93a1

If you don’t see results, query a Route 53 nameserver directly:

dig example.com A @ns-1234.awsdns-56.org +short

If 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 +short

You 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 json

Expected 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 +short

You 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.

Last modified on .