Route 53, DNS and ACM Certificates
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. See the section bibliography for the reference material consulted while preparing these pages. |
Commands and behaviour on this page are current for AWS CLI v2 (2.37 line), Amazon Route 53 and its VPC Resolver, the
Route 53 Global Resolver (generally available since 2026-03-09) and AWS Certificate Manager (ACM) with 198-day public
certificates, all checked on 2026-10-01; re-verify against aws --version and the linked reference pages before
relying on them in a pipeline. Examples use the placeholder domain example.com, the placeholder account ID
111122223333, placeholder hosted zone IDs such as Z1EXAMPLE and the Region us-east-1; all are stand-ins for
your own values.
Bookshelf needs three kinds of names. Visitors reach www.example.com, which must resolve to the bookshelf-cdn
CloudFront distribution over HTTPS. Browsers call api.example.com, which points at the alb-bookshelf Application
Load Balancer. Inside the VPC the services find each other as catalog.bookshelf.internal, a name that exists only
for the VPC. Amazon Route 53 is the DNS service that answers all three, and AWS Certificate Manager (ACM)
issues and renews the public TLS certificates that the CloudFront distribution and the load balancer present. This
page covers hosted zones, records, routing policies and health checks; DNSSEC; hybrid and remote DNS with Route 53
VPC Resolver and Global Resolver; domain registration; and ACM, including the Region rules that trip people up.
The distribution itself is on CloudFront and CDN Delivery, the load balancer and its listeners on
Load Balancers and Gateways, custom domains for API Gateway on
API Gateway, the VPC that private zones attach to on VPC Networking and
on-premises connectivity on VPN and Hybrid Connectivity. KMS keys, which DNSSEC signing
needs, are on Secrets Manager, Parameter Store and KMS.
Concepts
DNS translates a name into the data a client needs to connect (usually an IP address). A hosted zone is the
container Route 53 keeps for one domain and its subdomains: the set of records that say how to answer queries for
example.com and everything below it. Route 53 assigns each public hosted zone four name servers; they are
authoritative only once the parent zone (the domain registrar’s records for example.com) delegates to them.
| Term | Meaning |
|---|---|
Public hosted zone |
Answers queries from the internet. It is created as a container, delegated to from the registrar, and costs a monthly fee while it exists. |
Private hosted zone |
Answers queries only from the VPCs you associate with it, through the Route 53 VPC Resolver. The same name can exist as a public zone and a private zone (split-horizon DNS). |
Record |
One answer: a name, a type, a value or values and a TTL (how long resolvers may cache it). |
Alias record |
A Route 53 extension of the |
Routing policy |
The rule that chooses among several records with the same name and type (weighted, latency, failover, and so on). |
Health check |
A probe that Route 53 runs from several locations against an endpoint, another health check set or a CloudWatch alarm, so that routing policies can skip unhealthy answers. |
The record types you will meet:
| Type | Used for |
|---|---|
|
IPv4 and IPv6 addresses. Alias records use these types. |
|
A name that is an alias of another name. Not allowed at the zone apex or beside other records of the same name. |
|
Mail routing and free text: SPF, DKIM selectors, DMARC and domain-verification tokens (see Sending Email with Amazon SES). |
|
The zone’s name servers and start of authority; created automatically. An |
|
Which certificate authorities may issue for the domain; ACM public certificates are issued by Amazon (for example
|
|
Service location, reverse lookup, DNSSEC delegation signer and other less common data. |
The diagram is the whole story of DNS inside a VPC: workloads always ask the VPC Resolver, and the zones and rules you configure decide whether the answer comes from a private zone, from a network you forward to, or from public DNS.
Hosted zones
In the AWS Management Console
-
Open Route 53 → Hosted zones → Create hosted zone. Route 53 is a global service: the console does not show a Region selector for it, but private zones are associated with a VPC in a specific Region.
-
Enter the domain name
example.com, choose Public hosted zone and Create hosted zone. -
Open the zone and copy the four values of the
NSrecord. At your registrar, replace the name servers of the domain with these four values. If you registered the domain with Route 53 (see below) this is done for you in the zone Route 53 created at registration; creating a second zone for the same name does not change the delegation until you update the registered domain’s name servers. -
For a private zone, choose Private hosted zone, enter
bookshelf.internaland select the Region and the VPCvpc-bookshelfto associate. The VPC must have DNS resolution and DNS hostnames enabled. -
To use the same private zone from more VPCs, open the zone → Edit hosted zone → Associate VPC. For VPCs in another account, first authorize the association from the zone’s account (CLI below).
With the AWS CLI
export DOMAIN=example.com
# Public zone
ZONE_ID=$(aws route53 create-hosted-zone --name "$DOMAIN" \
--caller-reference "bookshelf-$(date +%s)" \
--query 'HostedZone.Id' --output text | cut -d/ -f3)
aws route53 get-hosted-zone --id "$ZONE_ID" --query 'DelegationSet.NameServers' # give these to the registrar
# Private zone, associated with the Bookshelf VPC
PRIVATE_ZONE_ID=$(aws route53 create-hosted-zone --name bookshelf.internal \
--caller-reference "bookshelf-private-$(date +%s)" \
--vpc VPCRegion=us-east-1,VPCId="$VPC_ID" \
--hosted-zone-config Comment="Bookshelf internal names",PrivateZone=true \
--query 'HostedZone.Id' --output text | cut -d/ -f3)
# Cross-account (or cross-Region) association: authorize from the zone's account, associate from the VPC's account
aws route53 create-vpc-association-authorization --hosted-zone-id "$PRIVATE_ZONE_ID" \
--vpc VPCRegion=us-east-1,VPCId="$OTHER_VPC_ID"
aws route53 associate-vpc-with-hosted-zone --hosted-zone-id "$PRIVATE_ZONE_ID" \
--vpc VPCRegion=us-east-1,VPCId="$OTHER_VPC_ID" # run with the other account's credentials
aws ec2 modify-vpc-attribute --vpc-id "$VPC_ID" --enable-dns-support '{"Value":true}'
aws ec2 modify-vpc-attribute --vpc-id "$VPC_ID" --enable-dns-hostnames '{"Value":true}'
Derived from
aws route53 create-hosted-zone,
aws route53 associate-vpc-with-hosted-zone
and Creating a private hosted zone.
The --caller-reference is any unique string that makes the call safe to retry. A private zone with the same name
as a public one hides the public records for clients inside the associated VPCs, so repeat every public record you
still want to resolve from inside. For many VPCs and accounts, Route 53 Profiles bundle private zones, Resolver
rules and DNS Firewall rule groups into one object that you share through AWS Resource Access Manager and associate
with VPCs, instead of associating each item one VPC at a time (a private zone supports up to 300 VPC associations
directly). The delegation takes effect as fast as the registrar’s parent zone propagates, typically minutes to a day
because of cached NS records.
Records and alias records
In the AWS Management Console
-
Open the hosted zone → Create record. Enter the record name (empty for the apex,
www,api), choose the type and the value, and the TTL (300 seconds is a common default; shorten it before a planned change). -
To point at an AWS resource, switch on Alias, choose the resource kind (for example Alias to CloudFront distribution or Alias to Application and Classic Load Balancer), the Region where relevant and the resource. Add an
AAAAalias too if the resource is dual-stack. -
Choose a routing policy (Simple routing is the default) and Create records. Use Define multiple records to add several at once.
-
Use Test record in the console, or the CLI
test-dns-answer, to see what Route 53 answers before you change the registrar.
With the AWS CLI
Changes are submitted as a change batch, atomically: either every change in the batch applies or none does.
# Alias target values: CloudFront has the fixed zone ID Z2FDTNDATAQYW2; load balancers have a per-Region ID
read ALB_DNS ALB_ZONE < <(aws elbv2 describe-load-balancers --names alb-bookshelf \
--query 'LoadBalancers[0].[DNSName,CanonicalHostedZoneId]' --output text)
cat > records.json <<EOF
{
"Comment": "Bookshelf public names",
"Changes": [
{ "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 } } },
{ "Action": "UPSERT", "ResourceRecordSet": {
"Name": "api.example.com", "Type": "A",
"AliasTarget": { "HostedZoneId": "$ALB_ZONE", "DNSName": "$ALB_DNS", "EvaluateTargetHealth": true } } },
{ "Action": "UPSERT", "ResourceRecordSet": {
"Name": "status.example.com", "Type": "CNAME", "TTL": 300,
"ResourceRecords": [ { "Value": "bookshelf.statuspage.example.net" } ] } }
]
}
EOF
CHANGE_ID=$(aws route53 change-resource-record-sets --hosted-zone-id "$ZONE_ID" \
--change-batch file://records.json --query ChangeInfo.Id --output text)
aws route53 wait resource-record-sets-changed --id "$CHANGE_ID"
aws route53 list-resource-record-sets --hosted-zone-id "$ZONE_ID" \
--query "ResourceRecordSets[?Type=='A'].[Name,AliasTarget.DNSName]" --output table
aws route53 test-dns-answer --hosted-zone-id "$ZONE_ID" --record-name api.example.com --record-type A
dig +short api.example.com
Derived from
aws route53 change-resource-record-sets,
aws route53 list-resource-record-sets
and Choosing between alias and non-alias records.
UPSERT creates the record or replaces it, which makes the batch re-runnable; CREATE fails if the record exists
and DELETE must match the existing record exactly. EvaluateTargetHealth on an alias to a load balancer makes
Route 53 treat the record as unhealthy when the load balancer has no healthy targets. A change is first
PENDING and becomes INSYNC when it has reached all Route 53 name servers, normally within about a minute;
resolvers that cached the old answer keep it until its TTL expires. One change batch may contain at most 1,000
record elements (an UPSERT counts twice) and 32,000 characters of values.
Routing policies
When several records share a name and type, the routing policy decides which answer Route 53 returns. Records of one name and type must all use the same policy and have a unique set identifier; policies other than simple can be combined through Traffic Flow (a visual policy editor and versioned traffic policies) or by nesting alias records that point at other records in the same zone.
| Policy | Use it for | Bookshelf example |
|---|---|---|
Simple |
One resource, or several values returned together in random order. |
|
Weighted |
Split traffic in proportions (0 to 255 per record), for canary releases and gradual migrations. |
Send 5 percent of |
Latency |
Send each user to the AWS Region with the lowest measured latency. |
|
Failover |
Active-passive: answer with the primary while its health check passes, otherwise the secondary. |
A static "maintenance" site in S3 as the secondary of |
Geolocation |
Answer by the user’s continent, country or US state, with a default record for everyone else. |
Serve a localized origin or block a market with a placeholder answer. |
Geoproximity |
Route by distance between users and resources, with a bias to attract or shed traffic; supports AWS Regions and custom coordinates (Traffic Flow, or the standard record API). |
Shift traffic gradually between two Regions. |
IP-based |
Route by the client’s IP address range, using a CIDR collection of your own ranges. |
Send a partner’s network ranges to a dedicated endpoint. |
Multivalue answer |
Return up to eight healthy records chosen at random; a lightweight client-side load distribution that is not a replacement for a load balancer. |
Several IPs of a self-managed service, health-checked. |
Latency, weighted, geolocation, geoproximity, multivalue and IP-based records may have up to 100 records with the same name and type (30 for geoproximity). Simple, weighted, latency, failover, geolocation, geoproximity and multivalue records can be used in private hosted zones. Latency, geolocation and geoproximity decisions depend on where the resolver is (or on the EDNS0 client subnet when the resolver sends it), not on the end user’s own location.
With the AWS CLI
# Weighted canary: 95 to the current load balancer, 5 to the new one
cat > weighted.json <<EOF
{
"Changes": [
{ "Action": "UPSERT", "ResourceRecordSet": {
"Name": "api.example.com", "Type": "A", "SetIdentifier": "current", "Weight": 95,
"AliasTarget": { "HostedZoneId": "$ALB_ZONE", "DNSName": "$ALB_DNS", "EvaluateTargetHealth": true } } },
{ "Action": "UPSERT", "ResourceRecordSet": {
"Name": "api.example.com", "Type": "A", "SetIdentifier": "canary", "Weight": 5,
"AliasTarget": { "HostedZoneId": "$NEW_ALB_ZONE", "DNSName": "$NEW_ALB_DNS", "EvaluateTargetHealth": true } } }
]
}
EOF
aws route53 change-resource-record-sets --hosted-zone-id "$ZONE_ID" --change-batch file://weighted.json
A failover pair adds "Failover": "PRIMARY" (with a HealthCheckId) to one record and "Failover": "SECONDARY"
to the other, and a latency pair adds "Region": "us-east-1" to each record. Derived from
Choosing a routing policy
and Configuring DNS failover.
For deployments that should shift traffic with request-level control instead of DNS, prefer weighted target groups on
the load balancer (see Load Balancers and Gateways) or CodeDeploy traffic shifting on
ECS Deployments, Scaling and Networking; DNS answers are cached, so a weight change is never
instantaneous.
Health checks
A Route 53 health check is run by checkers in several AWS Regions. There are three kinds:
-
Endpoint health checks probe an IP address or domain name over HTTP, HTTPS or TCP at an interval (30 seconds, or 10 seconds as the "fast" option at a higher price) and flip to unhealthy after a number of consecutive failures (three by default). HTTP(S) checks may require a string in the first 5,120 bytes of the response.
-
Calculated health checks combine up to 255 child checks with AND, OR or "at least N healthy".
-
CloudWatch alarm health checks follow the data behind an alarm, which is how you health-check something the internet-based checkers cannot reach, such as a resource in a private subnet: alarm on the target group’s healthy host count and point the health check at the alarm. An Application Recovery Controller routing-control check is a fourth option for deliberate manual failover.
In the AWS Management Console
-
Open Route 53 → Health checks → Create health check.
-
Name it
bookshelf-api, choose Endpoint, protocol HTTPS, domain nameapi.example.com, port443, path/actuator/healthand leave the interval at 30 seconds. -
Under Advanced configuration choose the failure threshold, whether to enable SNI and the checker Regions, and optionally add an alarm that sends an SNS notification (in
us-east-1) when the check fails. -
Attach it to a record from the record’s Health check field, or use it in a failover or weighted record.
With the AWS CLI
cat > health-check.json <<'EOF'
{
"Type": "HTTPS",
"FullyQualifiedDomainName": "api.example.com",
"Port": 443,
"ResourcePath": "/actuator/health",
"RequestInterval": 30,
"FailureThreshold": 3,
"EnableSNI": true
}
EOF
HC_ID=$(aws route53 create-health-check --caller-reference "bookshelf-api-$(date +%s)" \
--health-check-config file://health-check.json --query HealthCheck.Id --output text)
aws route53 update-health-check --health-check-id "$HC_ID" --failure-threshold 2
aws route53 get-health-check-status --health-check-id "$HC_ID" \
--query 'HealthCheckObservations[].[Region,StatusReport.Status]' --output table
Derived from
aws route53 create-health-check
and Types of Amazon Route 53 health checks.
Security groups and network ACLs must allow the checker IP ranges (published in ip-ranges.json under the
ROUTE53_HEALTHCHECKS service); the health check path should be a cheap, unauthenticated endpoint, ideally one that
verifies the dependencies the service cannot work without (see the Actuator health groups in
Metrics and Observability: Micrometer, Actuator, and Distributed Tracing). Health checks cost a monthly fee per check, more with
optional features, and only affect answers for records that reference them.
DNSSEC
DNSSEC lets resolvers verify that an answer came from your zone and was not altered. For a Route 53 public zone you
enable DNSSEC signing, create a key-signing key (KSK) backed by an asymmetric AWS KMS key (curve ECC_NIST_P256,
usage sign and verify) that must live in us-east-1, and then publish the zone’s DS record at the parent (the
registrar or the parent zone). Route 53 manages the zone-signing key itself. Registering the DS record is the step that
turns validation on for clients, so do it last and keep TTLs low during the rollout.
aws route53 create-key-signing-key --hosted-zone-id "$ZONE_ID" --name bookshelf-ksk \
--key-management-service-arn "arn:aws:kms:us-east-1:111122223333:key/<key-id>" \
--status ACTIVE --caller-reference "ksk-$(date +%s)"
aws route53 enable-hosted-zone-dnssec --hosted-zone-id "$ZONE_ID"
aws route53 get-dnssec --hosted-zone-id "$ZONE_ID" --query 'KeySigningKeys[0].DSRecord' --output text
Derived from aws route53 enable-hosted-zone-dnssec and Configuring DNSSEC signing in Amazon Route 53. The KMS key policy must allow the Route 53 DNSSEC service principal to use the key. Private hosted zones do not support DNSSEC signing, and an alias record’s answer is signed by Route 53 like any other.
Route 53 VPC Resolver, Profiles and Global Resolver
Every VPC has a DNS resolver at the VPC’s base address plus two (and 169.254.169.253). AWS documentation now calls
it the Route 53 VPC Resolver (it was Route 53 Resolver; the CLI namespace is still route53resolver). It answers
for private hosted zones associated with the VPC, for the ec2.internal/compute.internal style names of
instances, for VPC endpoints with private DNS, and for the public internet, and it follows any rules you add.
Hybrid DNS: endpoints and rules
-
An inbound endpoint gives on-premises resolvers IP addresses inside your VPC to which they can forward queries for names such as
catalog.bookshelf.internal. -
An outbound endpoint lets the VPC Resolver forward queries to your network. A forwarding rule names a domain (
corp.example.com) and the target resolver IPs; the rule applies to every VPC it is associated with. Rules and endpoints can be shared across accounts with AWS Resource Access Manager. A system rule keeps AWS-internal names resolving locally, and the most specific domain match among the rules wins. -
Each endpoint is a set of 2 or more network interfaces (up to 6 per endpoint, 4 endpoints per Region by default) across at least two Availability Zones, each handling thousands of queries per second.
-
Query logging sends the queries that VPCs make to CloudWatch Logs, S3 or Data Firehose, and Resolver DNS Firewall allows or blocks lookups of domain lists you provide or AWS managed lists, to stop data exfiltration over DNS.
OUT_ID=$(aws route53resolver create-resolver-endpoint --creator-request-id bookshelf-out \
--name bookshelf-outbound --direction OUTBOUND --security-group-ids "$RESOLVER_SG_ID" \
--ip-addresses SubnetId="$PRIVATE_SUBNET_A" SubnetId="$PRIVATE_SUBNET_B" \
--query ResolverEndpoint.Id --output text)
RULE_ID=$(aws route53resolver create-resolver-rule --creator-request-id bookshelf-corp \
--name corp-forward --rule-type FORWARD --domain-name corp.example.com \
--resolver-endpoint-id "$OUT_ID" --target-ips Ip=10.20.0.2,Port=53 \
--query ResolverRule.Id --output text)
aws route53resolver associate-resolver-rule --resolver-rule-id "$RULE_ID" --vpc-id "$VPC_ID" --name bookshelf-corp
aws route53resolver create-resolver-endpoint --creator-request-id bookshelf-in \
--name bookshelf-inbound --direction INBOUND --security-group-ids "$RESOLVER_SG_ID" \
--ip-addresses SubnetId="$PRIVATE_SUBNET_A" SubnetId="$PRIVATE_SUBNET_B"
Derived from aws route53resolver create-resolver-endpoint, aws route53resolver create-resolver-rule and What is Route 53 VPC Resolver?. The endpoint security group must allow TCP and UDP port 53 in the direction the endpoint handles. The transport that carries the traffic to the data centre (Site-to-Site VPN or Direct Connect) is on VPN and Hybrid Connectivity. Endpoints cost an hourly charge per network interface plus a per-query charge, so share them across VPCs with RAM or Profiles instead of creating one per VPC.
Route 53 Global Resolver
The Route 53 Global Resolver (generally available on 2026-03-09, in 30 Regions at launch) is an internet-reachable
DNS resolver with anycast IPv4 and IPv6 addresses for clients that are not inside a VPC: branch offices,
data centres and remote users and devices. It answers public names and the records of Route 53 private hosted zones
you associate with it (split-horizon), applies DNS filtering and DNSSEC validation, and logs queries in OCSF format.
Clients authenticate by source IP or CIDR (plain DNS on port 53, DNS over TLS or DNS over HTTPS) or by an access
token for DNS over TLS or HTTPS, and DNS views apply a different set of filtering rules to different groups of
clients. It is configured through the route53globalresolver CLI namespace in us-east-2:
aws route53globalresolver list-global-resolvers --region us-east-2
Derived from
aws route53globalresolver
and Key concepts and components for Route 53 Global Resolver.
For Bookshelf’s administrators connecting from laptops, Global Resolver is the resolver for
catalog.bookshelf.internal when they are not on the Client VPN described on
VPN and Hybrid Connectivity; a VPC Resolver inbound endpoint remains the right answer for a
data centre already connected by VPN or Direct Connect.
Domain registration
Route 53 is also a domain registrar (through Amazon Registrar and a registrar associate for some top-level domains).
Registering a domain, transferring one in, and managing its contacts, name servers, locks and renewal are all done
in the Route 53 Domains console pages or with the route53domains CLI, which is available only in us-east-1.
In the AWS Management Console
-
Open Route 53 → Domains → Registered domains → Register domains. Search for
example.com; choose up to five names and Proceed to checkout. -
Pick the registration period and whether Route 53 renews the domain automatically; enter the registrant, admin, technical and billing contacts and choose privacy protection (hides contact data in WHOIS where the TLD allows).
-
Submit, then open Domains → Requests and verify the registrant’s email address from the message Route 53 sends. An unverified registrant suspends the domain, which stops it resolving.
-
Route 53 creates a public hosted zone with the correct name servers automatically. To use another DNS provider, edit the domain’s name servers; to move the domain elsewhere, unlock it and request the transfer authorization code.
With the AWS CLI
aws route53domains check-domain-availability --region us-east-1 --domain-name example.com
aws route53domains get-domain-detail --region us-east-1 --domain-name example.com \
--query '[DomainName,AutoRenew,TransferLock,ExpirationDate,Nameservers[].Name]'
# Placeholder contact details in contact.json; registration is billed and not refundable
aws route53domains register-domain --region us-east-1 --domain-name example.com \
--duration-in-years 1 --auto-renew \
--admin-contact file://contact.json --registrant-contact file://contact.json --tech-contact file://contact.json
aws route53domains list-operations --region us-east-1 --status IN_PROGRESS
Derived from aws route53domains register-domain and Registering a new domain. A registered name cannot be changed afterwards, registrations and renewals are not refundable, a name with a TLD registry "premium" price cannot be registered through Route 53, and a new account starts with a quota of 20 domains. Do not use a domain registered in an AWS account as the email domain of that same account’s root user: if the account is suspended or closed, the domain is suspended too and the email you need to recover the account stops working. Register such domains in a separate management account or use a mailbox hosted elsewhere (see Accounts and Organizations).
AWS Certificate Manager
ACM provisions, stores, deploys and renews TLS certificates for AWS-integrated services, so Bookshelf never copies a private key onto a server.
| Kind | What it is |
|---|---|
Public certificate (ACM-issued) |
Issued by Amazon’s public certification authority, trusted by browsers. Free of charge when used with integrated services (CloudFront, Application and Network Load Balancer, API Gateway, App Runner, Elastic Beanstalk, Cognito and others). The private key stays inside ACM and the certificate is deployed by reference to its ARN. Publicly trusted certificates are valid for 198 days; ACM renews them automatically (older certificates with a 395-day validity are renewed 60 days before expiry and receive a 198-day period). |
Exportable public certificate |
A public certificate you can export with its private key for use on EC2, containers or on-premises servers, for an additional charge; renewals are automatic but you must redeploy the renewed certificate yourself. |
Private certificate |
Issued from an AWS Private CA for internal TLS and mutual TLS; the CA has a monthly charge. Not trusted by browsers. |
ACME-issued certificate |
Requested by a client such as Certbot from an ACM ACME endpoint, with domain ownership pre-approved by an administrator. The client holds the private key, so these cannot be attached to CloudFront, load balancers or API Gateway, and the client (not ACM) renews them. |
Imported certificate |
A certificate from another CA that you upload. ACM does not renew it; you replace it before it expires. |
Choosing the Region
ACM certificates are Regional resources. The service that uses the certificate decides the Region:
-
CloudFront: the certificate must be requested in
us-east-1(US East, N. Virginia), whatever Regions your origins are in. An edge-optimized API Gateway custom domain follows the same rule. -
Application, Network and Gateway Load Balancers, Regional API Gateway custom domains, App Runner and other Regional integrations: the certificate must be in the same Region as the resource. Request it once per Region you serve from, and renew-wise each Regional certificate is independent.
-
A certificate for the same name can exist in several Regions at the same time.
Validating domain ownership
ACM must see proof that you control each name before it issues a public certificate.
| Method | How it works |
|---|---|
DNS validation (recommended) |
ACM gives you a |
HTTP validation |
Only for certificates used with CloudFront distribution tenants (multi-tenant distributions): you place a redirect at
|
Email validation |
ACM mails five standard addresses ( |
In the AWS Management Console
-
Switch the Region selector to the right Region (US East (N. Virginia) for CloudFront) and open Certificate Manager → Request → Request a public certificate.
-
Enter
example.comand.example.com(add every name the certificate must cover; the default quota is 10 names per certificate), choose *DNS validation and the key algorithm (RSA 2048 is the default; ECDSA P-256 and P-384 are available), and Request. -
Open the certificate (status Pending validation) and choose Create records in Route 53. Within a few minutes the status becomes Issued.
-
Select the certificate on the CloudFront distribution, the HTTPS listener of the load balancer or the API Gateway custom domain by name; the console lists the certificates of the current Region.
-
Watch Renewal eligibility and In use on the certificate’s detail page. Certificates that are not in use by any integrated service are not renewed.
With the AWS CLI
CERT_ARN=$(aws acm request-certificate --region us-east-1 \
--domain-name "$DOMAIN" --subject-alternative-names "*.$DOMAIN" \
--validation-method DNS --tags Key=app,Value=bookshelf \
--query CertificateArn --output text)
# The validation record appears a few seconds after the request
aws acm describe-certificate --region us-east-1 --certificate-arn "$CERT_ARN" \
--query 'Certificate.DomainValidationOptions[0].ResourceRecord' > validation-record.json
jq '{Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:.Name,Type:.Type,TTL:300,ResourceRecords:[{Value:.Value}]}}]}' \
validation-record.json > validation-change.json
aws route53 change-resource-record-sets --hosted-zone-id "$ZONE_ID" --change-batch file://validation-change.json
aws acm wait certificate-validated --region us-east-1 --certificate-arn "$CERT_ARN"
aws acm describe-certificate --region us-east-1 --certificate-arn "$CERT_ARN" \
--query 'Certificate.[Status,RenewalEligibility,NotAfter,InUseBy]'
aws acm list-certificates --region us-east-1 \
--query 'CertificateSummaryList[].[DomainName,Status,CertificateArn]' --output table
Derived from
aws acm request-certificate,
aws acm describe-certificate
and AWS Certificate Manager DNS validation.
If the hosted zone is in another account or at another DNS provider, create the same CNAME there. The jq
filter only reshapes the record ACM returns into a change batch; it adds no data.
Renewal
ACM begins renewing a DNS-validated certificate 45 days before it expires, provided the certificate is in use by an
AWS service and every CNAME validation record is still present in public DNS. ARN, attachments and listeners
are unchanged, so nothing needs redeploying. If ACM cannot revalidate, it raises AWS Health and Amazon EventBridge
events at 30, 15, 7, 3 and 1 days before expiry; route those events to the Bookshelf operations topic. The most
common cause of an expiring certificate is a validation record deleted during a DNS clean-up or a zone migration.
Imported certificates and certificates not in use are not eligible for automatic renewal.
With CloudFormation
Keeping the zone, the certificate and the alias record in one template makes validation automatic: with
HostedZoneId in DomainValidationOptions, CloudFormation creates the validation record itself. A certificate for
CloudFront must be created in a stack that runs in us-east-1.
Parameters:
HostedZoneId: { Type: AWS::Route53::HostedZone::Id }
LoadBalancerDnsName: { Type: String }
LoadBalancerHostedZoneId: { Type: String }
Resources:
Certificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: api.example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: api.example.com
HostedZoneId: !Ref HostedZoneId
ApiRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostedZoneId
Name: api.example.com
Type: A
AliasTarget:
DNSName: !Ref LoadBalancerDnsName
HostedZoneId: !Ref LoadBalancerHostedZoneId
EvaluateTargetHealth: true
Outputs:
CertificateArn:
Value: !Ref Certificate
Derived from
AWS::CertificateManager::Certificate
and AWS::Route53::RecordSet.
The stack waits until the certificate is issued, so the first deployment takes a few minutes. The template language,
change sets and CDK equivalents (Certificate and ARecord constructs) are in
Infrastructure as Code.
Application code and permissions
Applications rarely edit DNS; the pipeline or an operator does. The exception in Bookshelf is ExternalDNS on EKS (see Deploying Microservices on EKS), which needs a role that can change records in one zone and nothing else:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["route53:ChangeResourceRecordSets"],
"Resource": ["arn:aws:route53:::hostedzone/Z1EXAMPLE"]
},
{
"Effect": "Allow",
"Action": ["route53:ListHostedZones", "route53:ListResourceRecordSets", "route53:ListTagsForResources"],
"Resource": ["*"]
}
]
}
Derived from Overview of managing access permissions to your Route 53 resources.
You can narrow ChangeResourceRecordSets further with the route53:ChangeResourceRecordSetsNormalizedRecordNames,
route53:ChangeResourceRecordSetsRecordTypes and route53:ChangeResourceRecordSetsActions condition keys. For
automation from Java, the AWS SDK for Java 2.x Route53Client issues the same change batch as the CLI (credentials
come from the default chain, for example the task or Pod Identity role):
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.route53.Route53Client;
import software.amazon.awssdk.services.route53.model.*;
public class ApiRecordPublisher {
public static void upsertApiAlias(String zoneId, String albDnsName, String albZoneId) {
try (Route53Client route53 = Route53Client.builder().region(Region.AWS_GLOBAL).build()) {
ResourceRecordSet recordSet = ResourceRecordSet.builder()
.name("api.example.com")
.type(RRType.A)
.aliasTarget(AliasTarget.builder()
.hostedZoneId(albZoneId)
.dnsName(albDnsName)
.evaluateTargetHealth(true)
.build())
.build();
route53.changeResourceRecordSets(ChangeResourceRecordSetsRequest.builder()
.hostedZoneId(zoneId)
.changeBatch(ChangeBatch.builder()
.changes(Change.builder().action(ChangeAction.UPSERT).resourceRecordSet(recordSet).build())
.build())
.build());
}
}
}
Derived from the Route53Client API reference. Spring Boot services do not manage certificates themselves: TLS ends at the load balancer or CloudFront with the ACM certificate, and traffic to the task can stay plain HTTP inside the VPC..
Pricing, limits and cost drivers
No prices are stated here; use the Route 53 pricing page, the ACM pricing page and the AWS Pricing Calculator for current figures (checked 2026-10-01).
-
Hosted zones: a monthly fee per zone, with an additional charge for zones above 10,000 records. A zone created and deleted within 12 hours of a domain registration is not charged.
-
Queries: charged per million, with different rates for standard, latency-based and geographic or geoproximity queries. Queries to alias records that target AWS resources are free, which is one more reason to prefer alias records over `CNAME`s for CloudFront and load balancers.
-
Health checks: a monthly fee per check, higher for non-AWS endpoints and for optional features (HTTPS, string matching, fast interval, latency measurement).
-
Domain registration: an annual fee that depends on the top-level domain; hosted zone charges for the zone Route 53 creates for the domain apply in addition.
-
VPC Resolver: an hourly charge per endpoint network interface plus per-query charges; DNS Firewall and query logging are priced separately (logging also incurs the destination’s charges). Global Resolver has its own pricing dimensions (see the Route 53 pricing page).
-
ACM: public certificates used with integrated services are free; exportable public certificates and AWS Private CA carry charges.
| Limit (default) | Value |
|---|---|
Hosted zones per account |
500, adjustable. |
Records per hosted zone |
10,000, adjustable (a surcharge applies above this). |
Active health checks per account |
200, adjustable. |
Domains registered per account |
20 for newer accounts (some older accounts have 50), adjustable. |
VPCs associated with one private hosted zone |
300 (use Route 53 Profiles for more). |
Resolver endpoints per Region / IPs per endpoint |
4 / 6. |
Resolver rules per Region |
1,000, adjustable. |
ACM certificates per Region |
2,500, adjustable; at most 5,000 requested in 365 days. |
Names per ACM certificate |
10 by default, up to 100 on request. |
Route 53 quotas are managed from the Service Quotas console in us-east-1; Resolver and ACM quotas are per
Region. aws route53 get-account-limit --type MAX_HEALTH_CHECKS_BY_OWNER and get-hosted-zone-limit show the current
values. Route 53 API calls are throttled per account: batch changes, retry with exponential backoff and avoid
creating one change per record in a loop.
Troubleshooting
| Symptom | Check |
|---|---|
|
The zone is not delegated to Route 53 (compare |
A change is not visible |
The change is |
|
A |
Alias to CloudFront or a load balancer answers but the page is a certificate error |
The certificate does not list the hostname, is in the wrong Region ( |
ACM certificate stuck in Pending validation |
The |
ACM renewal fails or "Renewal eligibility: INELIGIBLE" |
The certificate is not in use, was imported, or the validation |
Health check reports unhealthy while the site works |
Security groups or network ACLs block the checker ranges, the path needs authentication, the host header or SNI does not match, or the response takes longer than the check’s timeout. |
On-premises name does not resolve from the VPC (or the reverse) |
The rule is not associated with the VPC, the endpoint security group blocks port 53, the VPN or Direct Connect route is missing, or a more specific rule or private zone takes precedence. Enable Resolver query logging. |
Domain suspended |
The registrant’s email address was not verified; open Domains → Requests and complete the verification. |
Where older guides are outdated
-
Route 53 Resolver is now documented as Route 53 VPC Resolver, and Route 53 Profiles, Global Resolver and DNS Firewall are newer than most books and tutorials; the CLI namespaces
route53resolverandroute53globalresolverare the ones to use. -
ACM public certificates used to be valid for 13 months; the current validity is 198 days, renewed 45 days before expiry, and the CA/Browser Forum schedule means validity keeps shrinking. Automation, not calendar reminders, is the design.
-
Email validation is still available but is the weakest option; DNS validation renews without a human. HTTP validation for CloudFront multi-tenant distributions is new.
-
Many guides tell you to buy a certificate elsewhere or to import one into ACM for CloudFront. ACM public certificates are free for integrated services and renew themselves; ACM can now also export public certificates and issue them to ACME clients when you must run TLS outside AWS.
-
CNAMEat the apex does not work and was historically worked around with redirect hosts; use an alias record. -
Pointing a record at a load balancer’s or distribution’s IP address, found with
dig, breaks when AWS changes the addresses; use an alias record or the DNS name. -
Hosted zone names are not domain registrations: creating a zone does not register the domain and does not change delegation until the registrar’s name servers are updated.
Clean up
Delete in dependency order. A hosted zone cannot be deleted while it holds records other than its NS and SOA
records, and a certificate cannot be deleted while a distribution, listener or custom domain uses it.
# 1. Remove records (re-use the change batches with "Action": "DELETE"; values must match exactly)
aws route53 change-resource-record-sets --hosted-zone-id "$ZONE_ID" --change-batch file://records-delete.json
# 2. Health checks and DNSSEC
aws route53 delete-health-check --health-check-id "$HC_ID"
aws route53 disable-hosted-zone-dnssec --hosted-zone-id "$ZONE_ID"
aws route53 delete-key-signing-key --hosted-zone-id "$ZONE_ID" --name bookshelf-ksk
# 3. Hosted zones and VPC associations
aws route53 disassociate-vpc-from-hosted-zone --hosted-zone-id "$PRIVATE_ZONE_ID" --vpc VPCRegion=us-east-1,VPCId="$OTHER_VPC_ID"
aws route53 delete-hosted-zone --id "$PRIVATE_ZONE_ID"
aws route53 delete-hosted-zone --id "$ZONE_ID"
# 4. Resolver rules and endpoints (disassociate rules from VPCs first)
aws route53resolver disassociate-resolver-rule --resolver-rule-id "$RULE_ID" --vpc-id "$VPC_ID"
aws route53resolver delete-resolver-rule --resolver-rule-id "$RULE_ID"
aws route53resolver delete-resolver-endpoint --resolver-endpoint-id "$OUT_ID"
# 5. Certificates (after nothing uses them)
aws acm delete-certificate --region us-east-1 --certificate-arn "$CERT_ARN"
In the console: Route 53 → Hosted zones → select the zone → delete each record (not NS and SOA) →
Delete zone; Health checks → Delete; Resolver → Rules and Inbound/Outbound endpoints → Delete;
Certificate Manager → select the certificate → Delete. With CloudFormation, aws cloudformation delete-stack
removes the certificate, validation record and alias together. A registered domain is not deleted by any of this and
cannot be deleted through Route 53 while it is registered; turn off auto-renew
(aws route53domains disable-domain-auto-renew --region us-east-1 --domain-name example.com) if you do not want to
keep it. Remember to delete the validation CNAME only after the certificate is deleted, or the certificate cannot
renew. Derived from
aws route53 delete-hosted-zone
and aws acm delete-certificate.
Related pages
-
CloudFront and CDN Delivery uses the
us-east-1certificate and the alias record to the distribution. -
Load Balancers and Gateways attaches certificates to HTTPS listeners and explains the Regional rule.
-
API Gateway covers custom domain names, certificates and base-path mappings.
-
VPC Networking covers the VPC DNS attributes, interface endpoints with private DNS and Flow Logs.
-
VPN and Hybrid Connectivity covers the transport for hybrid DNS and Client VPN DNS.
-
Sending Email with Amazon SES uses
TXT,CNAMEandMXrecords for domain verification, DKIM, SPF and DMARC. -
Secrets Manager, Parameter Store and KMS covers KMS keys, including the one DNSSEC uses.
-
AWS Global Infrastructure explains edge locations, where Route 53 answers queries.
-
Deploying Microservices on EKS shows ExternalDNS publishing records for Kubernetes workloads.
-
Infrastructure as Code covers CloudFormation, CDK and Terraform for zones and certificates.