AWS Intermediate #5: Route 53 — domains and DNS

9 min read

After #4 RDS we had compute / storage / DB covered on the backend. Now we move to where users first meet our system — DNS. AWS’s managed DNS is Route 53 (named after TCP port 53 of DNS).

In this post we thread the big picture of DNS → Route 53’s shape → record types (especially Alias) → routing policies → health checks.

What DNS does — 5-second recap #

DNS maps example.com → IP. When the browser hits example.com, this happens.

DNS resolution flow
1. Browser: check `example.com` cache → none
2. OS: `/etc/hosts` → none
3. OS: system DNS resolver (router, or 1.1.1.1)
4. Resolver: cache check → none → root → .com TLD → example.com's NS
5. example.com's NS = Route 53 → A record → 192.0.2.10
6. Response travels back, caching along the way

Step 5 — the authoritative DNS for the domain — is Route 53.

TTL #

Each record has a TTL (Time To Live) — how long resolvers / browsers may cache.

TTLMeaning
30–60 secFrequently changing (fast failover recovery)
300 sec (5 min)Common production value
86400 (1 day)Rarely-changing NS / SOA

Higher TTL means faster responses and lower cost, but slower propagation. Operational cutovers typically lower TTL in advance.

Shape of Route 53 #

Route 53 has these parts:

ComponentRole
Domain RegistrationRegister / transfer domains (optional). Other registrars (gabia, GoDaddy, …) are fine too
Hosted ZoneAuthoritative DNS settings for the domain. The core component
Health CheckEndpoint monitoring. Linked to routing policies
ResolverDNS resolution within a VPC (rarely touched)

Domain registration vs Hosted Zone #

A common confusion. Where you bought the domain (registrar) and where DNS resolves it (Hosted Zone) are separate.

Pattern for a domain bought elsewhere with Route 53 DNS
Registrar (e.g., gabia):
  example.com NS = ns-1234.awsdns-56.com  ← point to Route 53 NS
                   ns-2345.awsdns-67.org
                   ns-3456.awsdns-78.net
                   ns-4567.awsdns-89.co.uk

Route 53 Hosted Zone:
  example.com.
    NS    ns-1234... (auto-generated)
    SOA   ... (auto-generated)
    A     www → 192.0.2.10
    A     api → 198.51.100.20

To migrate a domain from another registrar to Route 53 DNS:

  1. Create a Public Hosted Zone in Route 53 — auto-assigned 4 NS
  2. Enter those 4 NS in the registrar’s NS settings
  3. Wait for propagation (minutes to 24 hours)
  4. Verify with dig / nslookup

Hosted Zone types #

Public Hosted Zone #

Resolvable from anywhere on the internet. The common case.

Create a Public Hosted Zone
aws route53 create-hosted-zone \
  --name example.com \
  --caller-reference $(date +%s)

Private Hosted Zone #

DNS that resolves only inside a VPC. For internal service discovery.

Where Private Hosted Zone fits
Internal domains: api.internal.example.com → 10.0.10.100 (app EC2)
                  db.internal.example.com → RDS endpoint

EC2s inside the VPC can resolve these names; the public internet cannot. This makes it ideal for internal microservices.

Record types #

A / AAAA — domain to IP #

The basics:

A / AAAA records
A     api.example.com.    300   192.0.2.10        (IPv4)
AAAA  api.example.com.    300   2001:db8::10      (IPv6)

CNAME — domain to domain #

Alias to another domain.

Shape of CNAME
CNAME  www.example.com.    300   example.com.
CNAME  blog.example.com.   300   ghs.googlehosted.com.

Limits:

  • Can’t be on the root domain (example.com itself) ← DNS standard limit
  • A CNAME can’t coexist with other records (MX, TXT, …)

If you want to point the root domain at ALB / CloudFront, a CNAME won’t work. That’s where Alias comes in.

Alias — Route 53’s own thing #

Alias is a Route 53 invention — at response time it resolves to IPs just like an A / AAAA record. This works around the limitations of CNAME.

Where Alias fits
A   example.com.   ALIAS  d111111abcdef8.cloudfront.net    (CloudFront)
A   www.example.com. ALIAS my-alb-1234567890.elb.amazonaws.com  (ALB)
A   shop.example.com. ALIAS my-bucket.s3-website-ap-northeast-2.amazonaws.com (S3)

Properties:

  • Works on the root domain
  • Free (CNAMEs are charged per query, but Alias to AWS resources is free)
  • Auto IP refresh — ALB / CloudFront IPs change dynamically and Alias follows

Alias can only point to AWS resources (ALB, NLB, CloudFront, API Gateway, S3 website endpoint, other records in the same zone, etc.). For external domains, use CNAME.

MX — mail #

MX records
MX  example.com.   300   10 inbound-smtp.us-east-1.amazonaws.com.
                          20 inbound-smtp.us-east-2.amazonaws.com.

10, 20 are priorities — lower wins. Points at SES / Google Workspace / Microsoft 365 SMTP hosts.

TXT — text #

Domain verification / SPF / DKIM, etc.

Common TXT uses
TXT   example.com.   300   "v=spf1 include:_spf.google.com ~all"
TXT   _dmarc.example.com. 300  "v=DMARC1; p=quarantine; rua=mailto:..."
TXT   _acme-challenge.example.com. 300  "lemonjuice123..." (Let's Encrypt verification)

NS / SOA — automatic #

Auto-created when the Hosted Zone is made. Hardly touched.

CAA — cert-issuance authority #

Restricts which CAs can issue certs for this domain.

CAA — only allow Amazon ACM
CAA  example.com.  300  0 issue "amazon.com"

If CAA blocks ACM (#6) issuance, requests fail.

Routing policies — Route 53’s real charm #

You can answer the same domain with different IPs under different conditions.

1) Simple Routing #

Simplest. One domain → one or many IPs. Multiple IPs round-robin.

2) Weighted Routing — split by weight #

Assign weights to records to split traffic by ratio. Attractive for canary deploys.

Weighted routing — v1 90% / v2 10%
A   api.example.com   ALIAS   alb-v1.elb...   weight=90
A   api.example.com   ALIAS   alb-v2.elb...   weight=10

3) Latency Routing — closest region wins #

Same service in multiple regions, route users to the closest region.

Latency routing
A   api.example.com   ALIAS   alb-seoul...   region=ap-northeast-2
A   api.example.com   ALIAS   alb-tokyo...   region=ap-northeast-1
A   api.example.com   ALIAS   alb-tokyo...   region=us-east-1

Korean users → Seoul, Japanese → Tokyo, US → Virginia.

4) Failover Routing — automatic failover #

Primary / Secondary pair, fail over to Secondary when Primary’s health check fails.

Failover routing — for DR
A   api.example.com   ALIAS   alb-prod-seoul...   PRIMARY   health-check=HC1
A   api.example.com   ALIAS   alb-dr-tokyo...     SECONDARY

5) Geolocation Routing — by country / continent #

Route by user’s geographic location. For compliance / content differences.

Geolocation
A   api.example.com   ALIAS   alb-kr...   geolocation=KR (Korea)
A   api.example.com   ALIAS   alb-jp...   geolocation=JP (Japan)
A   api.example.com   ALIAS   alb-default... geolocation=DEFAULT (the rest)

6) Geoproximity Routing #

Geolocation plus a configurable bias. AWS’s routing algorithm is more nuanced here — rarely used in practice.

7) Multivalue Answer Routing #

Returns multiple IPs randomly. Combined with health checks, returns only live IPs. Simple client-side load balancing.

Decision guide #

Decision tree
One target only → Simple
Need to split rollout ratio → Weighted
Want closest of many regions → Latency
DR / backup → Failover
Country-level compliance → Geolocation
DNS-level load balance → Multivalue

Health Check #

Routing policies’ core companion. Checks the endpoint every 30 seconds.

Create a Health Check
aws route53 create-health-check \
  --caller-reference $(date +%s) \
  --health-check-config '{
    "Type": "HTTPS",
    "FullyQualifiedDomainName": "api.example.com",
    "ResourcePath": "/health",
    "Port": 443,
    "RequestInterval": 30,
    "FailureThreshold": 3
  }'

Types:

  • HTTP / HTTPS / TCP — direct endpoint checks
  • Calculated — AND / OR composition of other checks
  • Based on CloudWatch Alarm — judge by alarm state

Health Check uses #

  • Trigger automatic switching for Failover routing
  • Filter live IPs for Multivalue routing
  • Standalone is possible but usually combined with routing

Domain operations — common patterns #

1) Main site + subdomains #

Common setup for example.com
A      example.com.        ALIAS   www.example.com.    (root → www)
A      www.example.com.    ALIAS   d111...cloudfront.net
A      api.example.com.    ALIAS   alb-prod...elb.amazonaws.com
A      app.example.com.    ALIAS   d222...cloudfront.net
TXT    _dmarc.example.com. "v=DMARC1; p=reject; ..."
MX     example.com.        10 inbound-smtp.ses-us-east-1.amazonaws.com.

2) Per-environment splits #

Per-environment subdomains
api.dev.example.com       ← dev environment ALB
api.staging.example.com   ← staging
api.example.com           ← prod

Or use separate Hosted Zones for dev.example.com — cleaner permission delegation.

3) Apex (root) ALB / S3 #

Apex domains that can’t use CNAME use Alias instead. The ALB’s hosted zone is matched automatically via a drop-down in the console.

Cost #

ItemCost
Hosted Zone$0.50 / month (first 25)
Query (standard)$0.40 / million
Query (latency / geo, etc.)$0.60 / million
Health Check (AWS endpoint)$0.50 / month
Health Check (external / HTTPS)$0.75 / month + options
Domain registration$9+ / year per TLD

A small site is around $1–2/month.

Common pitfalls #

1) Forgot to update NS, only edited Route 53 #

You created the Hosted Zone but the registrar’s NS still points to the old place — nothing reflects. Make sure you entered the 4 NS in the registrar.

Check the NS in effect
dig NS example.com +short

2) Trying CNAME on the apex #

example.com CNAME myapp.heroku.com → rejected. Alias only points to AWS resources. If an external service (Heroku, etc.) needs the root domain, either the service offers Alias-like functionality (e.g., CloudFlare CNAME flattening), or use a redirector pattern (S3 redirect → apex → www).

3) TTL too long, slow cutover #

Right before an operational cutover (e.g., an ALB swap), lower the TTL to ~60 sec, then raise it back once things are stable. Without lowering it in advance, the old IP can linger in caches for up to 24 hours.

4) Health check false positive #

A check path that requires auth always returns 401 → unhealthy. Use a public path like /health.

5) Failover with no health check #

PRIMARY without a health check won’t auto-fail-over. Forgetting “evaluate target health” in the console is a common mistake.

6) Enabling DNSSEC and forgetting #

Forgetting to rotate DNSSEC’s KSK / ZSK kills domain resolution outright. Enable carefully / with automation.

7) Private Hosted Zone not resolving in VPC #

If VPC’s enableDnsHostnames / enableDnsSupport are off, the Private Hosted Zone won’t resolve. Confirm both are true.

8) MX priority typo #

Missing the 10 in MX 10 mail.example.com. breaks resolution outright.

Wrap-up #

What we took home this time:

  • Route 53 = AWS’s managed DNS. Domain Registration / Hosted Zone / Health Check / Resolver — the four parts
  • Domain registrarHosted Zone are separate. Pointing the registrar’s NS to Route 53 NS is the start
  • Public Hosted Zone = internet, Private Hosted Zone = VPC-only
  • Common records: A / AAAA / CNAME / TXT / MX / NS / SOA / CAA
  • Alias is Route 53’s own thing — works on the root domain, free for AWS resources, auto IP refresh
  • 7 routing policies — Simple / Weighted / Latency / Failover / Geolocation / Geoproximity / Multivalue
  • Health Check triggers Failover / Multivalue switching
  • Operational patterns — per-env subdomains / separate Hosted Zones / Alias on apex
  • Pitfalls — NS update, apex CNAME, cutover with high TTL, false-positive HC, Failover without HC, Private Hosted Zone DNS opts, MX syntax

Next — ALB / NLB / ACM #

The DNS piece is set. Now the place that domain points to — load balancer and HTTPS.

In #6 ALB / NLB and ACM (HTTPS) we’ll line up the differences between ALB / NLB / GWLB, the Listener / Target Group / Health Check flow, ACM cert issuance and auto-renewal, and the operational patterns of HTTPS.

X