Production DNS & TLS with Route 53 and ACM
Take a site from an IP address to a real domain over HTTPS, with a certificate that renews itself.
- Time
- 50 min
- Level
- Intermediate
- Objectives
- 4 objectives
- Cost
- Low cost
Before you start
You will need
- AWS CLI v2, configured
- A domain you control
You will be able to
- Choose between A, CNAME and ALIAS records deliberately
- Validate an ACM certificate by DNS and understand why it renews
- Plan a cutover around TTL instead of being surprised by it
Cost — Low cost
Low. A Route 53 hosted zone is $0.50/month and queries are fractions of a cent. ACM certificates are free. A domain, if you do not have one, is roughly $12/year.
Success criteria
0 of 4
The scenario#
The platform is reachable at d3bbb7tnfglcfh.cloudfront.net. That is fine for a test and unusable for anything real.
This is the same work that put egykode.com in front of this page, including the mistake that cost an hour.
1. A hosted zone#
aws route53 create-hosted-zone --name example.com \
--caller-reference "$(date +%s)" \
--query 'DelegationSet.NameServers' --output tablePoint your registrar's nameservers at those four. Until that propagates, Route 53 is authoritative for a domain nobody asks it about.
dig NS example.com +short # must return the Route 53 nameservers2. A certificate, validated by DNS#
ARN=$(aws acm request-certificate --domain-name example.com \
--subject-alternative-names "www.example.com" \
--validation-method DNS --region us-east-1 \
--query CertificateArn --output text)
aws acm describe-certificate --certificate-arn "$ARN" --region us-east-1 \
--query 'Certificate.DomainValidationOptions[].ResourceRecord' --output tableus-east-1 regardless of where anything else runs — CloudFront only accepts certificates from that region, and a certificate in the wrong one simply does not appear in the console dropdown.
Create the CNAME it prints, then:
aws acm wait certificate-validated --certificate-arn "$ARN" --region us-east-1Leave the validation record in place forever. ACM re-checks it to renew automatically; delete it and the certificate silently stops renewing, which surfaces thirteen months later as an outage.
3. The records#
{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d3bbb7tnfglcfh.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}]
}A | CNAME | ALIAS | |
|---|---|---|---|
| Points at | A fixed IP | Another name | An AWS resource |
| Allowed at the apex | Yes | No | Yes |
| Follows a changing target | No | Yes | Yes |
| Query cost | — | Billed | Free |
The apex restriction is not an AWS quirk: DNS forbids a CNAME alongside the
SOA and NS records every zone apex must have. ALIAS is Route 53 resolving it
internally, which is why it works there and a CNAME does not.
Z2FDTNDATAQYW2 is CloudFront's fixed hosted zone id — the same for every
distribution, and worth recognising rather than looking up each time.
4. Verify all four layers#
dig example.com +short
curl -sI https://example.com | head -3
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -subject -dates5. TTL, and cutovers#
dig example.com | grep -A1 "ANSWER SECTION"The number before the record type is the remaining TTL. Resolvers everywhere will keep serving the old answer until it expires.
Lower the TTL a day before a migration, not during it. Lowering it at cutover changes nothing for anyone already holding the old record at the old long TTL — which is the single most common DNS migration mistake.
When it goes wrong#
The certificate stays PENDING_VALIDATION
The CNAME is wrong or proxied. Many DNS providers append the zone automatically — paste the name without it, and check with dig.
CloudFront will not offer your certificate
It is not in us-east-1. Certificates for CloudFront must be requested there whatever region your other resources use.
CNAMEAlreadyExists when adding the alias
Another distribution already claims that alternate name. Remove it there first.
Old content after the cutover
The TTL has not expired. dig shows the remaining seconds; nothing you change makes a cached answer expire sooner.
Clean up#
Run this even if you did not finish.
Destructive — This removes real resources. Check which environment you are in first.
aws route53 list-resource-record-sets --hosted-zone-id <id>
# Delete non-default records, then the zone (a hosted zone bills monthly):
aws route53 delete-hosted-zone --id <id>
aws acm delete-certificate --certificate-arn <arn>Cost of this lab: Low. A Route 53 hosted zone is $0.50/month and queries are fractions of a cent. ACM certificates are free. A domain, if you do not have one, is roughly $12/year.
The concept behind it
Next up
Lab 17 of 58 on the project path