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 A/AAAA types that points at an AWS resource (CloudFront distribution, load balancer, API Gateway custom domain, S3 website endpoint, Elastic Beanstalk environment, Global Accelerator, another record in the same zone). It works at the zone apex, where a CNAME is not allowed, follows the resource when its addresses change, and queries to alias records that target AWS resources are not charged.

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

A, AAAA

IPv4 and IPv6 addresses. Alias records use these types.

CNAME

A name that is an alias of another name. Not allowed at the zone apex or beside other records of the same name.

MX, TXT

Mail routing and free text: SPF, DKIM selectors, DMARC and domain-verification tokens (see Sending Email with Amazon SES).

NS, SOA

The zone’s name servers and start of authority; created automatically. An NS record at a subdomain delegates that subdomain to other name servers.

CAA

Which certificate authorities may issue for the domain; ACM public certificates are issued by Amazon (for example amazon.com, amazontrust.com, awstrust.com, amazonaws.com), so add those values if you publish CAA.

SRV, NAPTR, PTR, SPF, DS, SSHFP, TLSA, SVCB, HTTPS

Service location, reverse lookup, DNSSEC delegation signer and other less common data.

flowchart LR APP["Task, function or instance in the VPC"] --> R["VPC Resolver (VPC base address + 2)"] R --> M{"Most specific match for the name"} M -- "private hosted zone" --> PHZ["Answer from the private zone, for example catalog.bookshelf.internal"] M -- "forwarding rule" --> OUT["Outbound endpoint"] --> ONPREM["On-premises DNS server"] M -- "nothing specific" --> PUB["Public DNS, including Route 53 public zones"] CORP["On-premises client"] --> IN["Inbound endpoint"] --> R

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

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

  2. Enter the domain name example.com, choose Public hosted zone and Create hosted zone.

  3. Open the zone and copy the four values of the NS record. 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.

  4. For a private zone, choose Private hosted zone, enter bookshelf.internal and select the Region and the VPC vpc-bookshelf to associate. The VPC must have DNS resolution and DNS hostnames enabled.

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

  1. 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).

  2. 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 AAAA alias too if the resource is dual-stack.

  3. Choose a routing policy (Simple routing is the default) and Create records. Use Define multiple records to add several at once.

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

www to the CloudFront distribution.

Weighted

Split traffic in proportions (0 to 255 per record), for canary releases and gradual migrations.

Send 5 percent of api traffic to a new load balancer while testing.

Latency

Send each user to the AWS Region with the lowest measured latency.

api in us-east-1 and eu-west-1 if Bookshelf ran in two Regions.

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

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

  1. Open Route 53 → Health checks → Create health check.

  2. Name it bookshelf-api, choose Endpoint, protocol HTTPS, domain name api.example.com, port 443, path /actuator/health and leave the interval at 30 seconds.

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

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

  1. Open Route 53 → Domains → Registered domains → Register domains. Search for example.com; choose up to five names and Proceed to checkout.

  2. 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).

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

  4. 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 CNAME record per unique name (_<token>.example.com pointing at an ACM validation name). Create it once in the public hosted zone (the console button Create records in Route 53 does so) and ACM issues the certificate and renews it automatically for as long as the certificate is in use and the record stays in place. A wildcard and its apex (example.com and *.example.com) share one record. ACM cannot validate names in private hosted zones.

HTTP validation

Only for certificates used with CloudFront distribution tenants (multi-tenant distributions): you place a redirect at /.well-known/pki-validation/ that points at an ACM-controlled location. Wildcards are not supported.

Email validation

ACM mails five standard addresses (admin@, hostmaster@, and so on) of the domain and each renewal needs a human to click a link, starting 45 days before expiry. Use it only if you cannot edit DNS. A certificate validated by email cannot be switched to DNS; request a new one.

In the AWS Management Console

  1. Switch the Region selector to the right Region (US East (N. Virginia) for CloudFront) and open Certificate Manager → Request → Request a public certificate.

  2. Enter example.com and .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.

  3. Open the certificate (status Pending validation) and choose Create records in Route 53. Within a few minutes the status becomes Issued.

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

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

NXDOMAIN for a name you created

The zone is not delegated to Route 53 (compare dig NS example.com with the zone’s name servers), the record is in a different hosted zone with the same name, or a private zone with the same name hides the public record inside the VPC.

A change is not visible

The change is PENDING (aws route53 get-change), or resolvers still hold the old answer until the TTL expires. Lower the TTL a day before a planned change.

InvalidChangeBatch, "RRSet with DNS name …​ is not permitted at apex" or a CNAME conflict

A CNAME cannot sit at the apex or beside another record with the same name; use an alias record.

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 (us-east-1 for CloudFront), or is not attached to the listener or distribution.

ACM certificate stuck in Pending validation

The CNAME is missing, in a private zone, at a different provider than the one that serves the domain, or a CAA record forbids Amazon. A request not validated within 72 hours moves to Validation timed out; request again.

ACM renewal fails or "Renewal eligibility: INELIGIBLE"

The certificate is not in use, was imported, or the validation CNAME was deleted. Restore the record; watch the EventBridge events listed above.

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 route53resolver and route53globalresolver are 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.

  • CNAME at 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.