### The two questions every global-facing app has to answer A food delivery app built for Bengaluru launches in Dubai. Every request from a Dubai user crosses an ocean twice - once to reach the Mumbai origin, once for the response. Page loads that felt instant at home take three seconds abroad. Nobody changed the code. The architecture just never accounted for where users actually are. This is the exact gap Route 53 and CloudFront exist to close, and they solve two genuinely different problems that get confused constantly. * **Route 53** answers "which IP address should this name point to, and should that answer change based on health, location, or load?" It is a DNS service - it never touches the actual traffic, only the lookup that happens before the traffic. * **CloudFront** answers "once the client knows the IP, how do we get the actual bytes to them fast?" It is a CDN - it caches and forwards the real request/response traffic. User types: app.zomato-clone.com -> Route 53 answers: "here is the IP to connect to" (DNS lookup, no data yet) -> Client connects to that IP -> CloudFront Edge Location serves the actual content (real traffic, cached or forwarded) > 📌 **Remember:** Route 53 handles DNS queries and DNS-based routing decisions - it does not proxy or touch your application's HTTP or TCP traffic. CloudFront is the layer that actually receives requests and serves responses. ### Why this module groups them together They are frequently deployed as a pair: a Route 53 Alias record points a domain at a CloudFront distribution, which then fetches from an origin protected by ACM certificates and WAF rules. Understanding one without the other leaves a gap - you can configure perfect DNS routing and still serve slow, uncached content, or run a perfectly tuned CDN that nobody can discover because the DNS behind it is misconfigured. ### How this connects to the databases module The databases module covered choosing the right backend for your data. This module covers what happens between the user and that backend - and it directly affects what your database sees. For cacheable content and appropriately configured API responses, CloudFront can absorb repeated requests at the edge, reducing the number of requests that ever reach your ALB, application, and ultimately your RDS or DynamoDB tables. CloudFront only caches responses that are actually eligible for caching - it does not automatically turn arbitrary database-backed API traffic into cached content without deliberate cache policy configuration. ---
### What actually happens when you type a domain name Nobody types IP addresses. A user types `zomato-clone.com` and expects it to just work. DNS is the system that translates that name into the IP address a browser can actually connect to. ```text 1. Browser checks local cache -> not found 2. Asks Local DNS Resolver (ISP or 8.8.8.8) 3. Resolver asks Root DNS Server -> "try the .com TLD server" 4. Resolver asks .com TLD Server -> "try zomato-clone.com's Name Server" 5. Resolver asks the Authoritative Name Server -> "it's 93.184.216.34" 6. Resolver returns the IP, caches it for the TTL duration 7. Browser connects to 93.184.216.34 ``` This entire chain typically resolves in milliseconds, and caching at every layer means most lookups skip straight to step 1. > **Note:** An **Authoritative Name Server** is the final source of truth for a domain's records - it is the server that actually holds the answer, as opposed to a resolver that is just relaying a cached or looked-up answer on your behalf. ### What Route 53 actually is **Route 53** is AWS's authoritative DNS service - authoritative meaning you control the records directly and Route 53 is the source of truth AWS returns to the world. It is also a **domain registrar**, so you can buy and manage a domain in the same place you configure its DNS, though the two roles are separate and do not have to live with the same provider. * AWS publishes an availability SLA for the Route 53 DNS service - check the current AWS SLA page for the exact figure, since SLA terms can change over time * Named for port 53, the standard DNS port * Billed per hosted zone per month, plus a small per-query cost ### Hosted zones - public versus private A **Hosted Zone** is the container holding all DNS records for a domain and its subdomains. **Public Hosted Zone** answers queries from anywhere on the internet - this is what you use for any customer-facing domain. **Private Hosted Zone** only answers queries from inside the VPCs you associate it with - this is how internal services find each other by name instead of hardcoded private IPs. ```text Public Hosted Zone (zomato-clone.com) -> resolves for any internet client -> points to: ALB, CloudFront, S3 website Private Hosted Zone (internal.zomato-clone.com) -> only resolves inside associated VPCs -> db.internal.zomato-clone.com -> 10.0.4.20 (RDS) -> cache.internal.zomato-clone.com -> 10.0.4.31 (ElastiCache) ``` > 💡 **Tip:** A private hosted zone is a clean way to stop hardcoding internal IPs in application config. Services reference each other by name, and the underlying IP can change without touching application code. ---
### The record types you actually use daily Every DNS record has a name, a type, a value, and (with one exception) a TTL. * **A Record** - maps a hostname to an IPv4 address: `app.zomato-clone.com -> 3.6.12.44` * **AAAA Record** - the same mapping for IPv6 * **NS Record** - tells the internet which name servers are authoritative for this domain; this is what you update at your registrar when moving DNS management to Route 53 * Beyond these, MX, TXT, CAA, and SOA exist for mail routing, verification, and zone metadata - worth knowing they exist, rarely hand-configured day to day ### The CNAME limitation that trips up every beginner once A **CNAME** record points a hostname to another hostname, not directly to an IP. The critical rule: a CNAME can never be set on the root domain (the "zone apex"). ```text Works: www.zomato-clone.com -> mycdn.cloudfront.net (subdomain, fine) Fails: zomato-clone.com -> mycdn.cloudfront.net (root domain, not allowed) ``` This is a DNS protocol rule, not an AWS limitation - it exists because the root domain also needs to hold NS and SOA records, and CNAME cannot coexist with other record types on the same name. ### Alias records - AWS's answer to the CNAME problem AWS resources expose DNS hostnames that can change (an ALB's underlying IPs rotate, for instance), and you often want your root domain itself to point at one of them - something CNAME cannot do. **Alias Record** solves both problems: it works on the root domain, and it lets Route 53 map a name directly to a supported AWS resource without you having to manage or track that resource's underlying IP addresses. | | CNAME | Alias | |:---|:---|:---| | Works on root domain | No | Yes | | Query cost | Billed | Free | | TTL | Required | Managed automatically by Route 53 | | Valid targets | Any hostname | Only specific AWS resources | **Valid Alias targets** include Elastic Load Balancers, CloudFront distributions, API Gateway, and a growing list of other AWS-integrated services - consult the current Route 53 documentation for the complete, up-to-date list, since supported targets are occasionally added. > 📌 **Remember:** An EC2 instance's public DNS name is not a valid Alias target. If your origin is a bare EC2 instance rather than a load balancer, you point at it with an A record and its IP, not an Alias. ### TTL and the safe way to change a record TTL is how long a resolver caches your answer before asking again. High TTL means cheaper, more cached lookups but slower propagation of changes. Low TTL means faster propagation but more queries hitting Route 53. ```text Safe DNS change procedure: 1. Lower TTL to 60 seconds 2. Wait 24-48 hours so existing cached clients pick up the new low TTL 3. Make your actual DNS change 4. Give the old TTL window time to fully expire across resolvers 5. Raise TTL back to its normal value ``` > 🔴 **Common Mistake:** Changing a record's value without lowering TTL first, or assuming a change is visible everywhere the moment it is made. After the TTL expires, resolvers that cached the old record can begin retrieving the new value - but actual visibility varies by resolver, cached state, and negative caching behavior, not a guaranteed universal cutover moment. Clients that cached the old value under a 24-hour TTL can keep using the stale answer for up to that long after your change. ---
### What a health check actually monitors A **Route 53 Health Check** continuously probes a resource and reports healthy or unhealthy, which several routing policies use to automatically stop sending traffic to a failing endpoint. Health checks work directly only against **public** resources - checkers run from outside your VPC. * Checks originate from a global set of checker locations for redundancy against any single network path failing * Protocol: HTTP, HTTPS, or TCP * Default check interval is 30 seconds; a faster interval is available at higher cost * HTTP/HTTPS health checks can validate the endpoint's response status and, where configured, look for specific text in the response body - check current AWS documentation for the exact response codes and behavior your configuration relies on ### Calculated health checks - combining multiple signals A **Calculated Health Check** combines several child health checks into one parent result using AND, OR, or NOT logic, and lets you specify how many children must pass for the parent to report healthy. > 💡 **Tip:** This is the pattern for taking one instance down for maintenance without tripping a failover alarm - configure the parent to tolerate one child being unhealthy, and planned maintenance on a single node no longer looks like an outage to Route 53. ### Monitoring resources that are not publicly reachable Route 53's checkers cannot reach into a private VPC directly, since they run from outside it. The general pattern for extending health visibility to a private resource is to route its health signal through CloudWatch: ```text Private resource (e.g. EC2 in a private subnet) -> emits a CloudWatch Metric (CPU, error rate, or a custom app metric) -> CloudWatch Alarm evaluates that metric against a threshold -> Route 53 Health Check can be configured to reflect that Alarm's state ``` > **Note:** Treat this as the general shape of the solution rather than a fixed recipe - the exact configuration steps for wiring a Route 53 health check to a CloudWatch Alarm are worth checking against current AWS documentation before implementing. The reliability of the whole chain is only as good as the metric and alarm threshold behind it; a threshold set too loosely means Route 53 can keep reporting healthy long after the resource has actually degraded. ---
### Why one routing policy rarely covers a whole architecture Route 53 supports eight distinct routing policies, and picking the right one for each record - not one policy for the whole domain - is the actual skill being tested here. A production setup commonly layers several: failover between regions, weighted rollout within a region, and latency-based routing deciding which region a user reaches first. ### Simple routing - one answer, no health checks Returns one resource, or multiple values where the client picks one at random. No health check support. ```text Client asks for foo.zomato-clone.com Route 53 returns 3 IPs -> client picks one at random and connects ``` Use for a single-resource setup with no failover requirement. ### Weighted routing - splitting traffic by percentage Assigns each record a relative weight; traffic share equals that record's weight divided by the sum of all weights for that record set. Weights do not need to add up to 100. ```text app.zomato-clone.com -> 11.22.33.44 (Weight 70) -> ~70% of traffic app.zomato-clone.com -> 55.66.77.88 (Weight 20) -> ~20% of traffic app.zomato-clone.com -> 99.11.22.33 (Weight 10) -> ~10% of traffic ``` Use for canary releases, blue-green rollouts, and A/B testing. Setting a record's weight to 0 stops routing to it without deleting the record. ### Latency-based routing - fastest region wins Routes to the AWS Region with the lowest measured latency for that user, based on latency measurements between users and Regions, not geographic distance - a user can genuinely get faster service from a farther region depending on network paths. ```text User in Mumbai: ap-south-1: 12ms us-east-1: 180ms eu-west-1: 210ms -> Route 53 returns ap-south-1 ``` Combine with health checks so a low-latency but unhealthy region gets skipped in favor of the next-best healthy one. ### Failover routing - active-passive disaster recovery Requires a mandatory health check on the primary record. While the primary is healthy, Route 53 always returns it; the moment it fails, Route 53 automatically starts returning the secondary instead - no manual intervention. ```text Healthy: Client -> Route 53 -> Primary (always) Failure: Primary health check fails -> Route 53 automatically returns Secondary ``` ### Geolocation routing - based on where the user is Routes based on the user's detected physical location - by continent, country, or US state - not network performance. Always define a default record for users whose location matches no explicit rule, or those users get no answer at all. ```text User in Germany -> EU record (regional content, language) User in India -> AP record Everyone else -> Default record ``` > 📌 **Remember:** Geolocation and latency-based routing solve different problems and are easy to conflate. Geolocation asks "where is this user physically." Latency-based asks "which region responds to this user fastest." A user can be physically close to a region and still get lower latency from a farther one. ### Geoproximity routing - shifting coverage with bias Routes based on the geographic location of both the user and the resource, and lets you nudge how much territory each resource claims using a **bias** value. Positive bias expands a resource's coverage area; negative bias shrinks it. This requires the **Route 53 Traffic Flow** feature rather than plain console record creation. ```text Migrating load from us-west-1 to us-east-1: Start: both at bias 0 -> traffic splits by pure proximity Increase us-east-1 bias to +50 -> its effective coverage zone expands -> more geographically distant users now get routed there ``` ### IP-based routing - routing by client network Maps specific CIDR ranges of client IPs to specific endpoints, useful for optimizing a known ISP's users or reducing cross-network data transfer costs for a particular network. ```text Client from 203.0.113.0/24 -> Endpoint A Client from 200.5.4.0/24 -> Endpoint B ``` ### Multi-value routing - client-side selection among healthy endpoints Returns up to eight healthy records per query, each optionally tied to its own health check; unhealthy records are automatically excluded from what gets returned. This is not a load balancer - the client still picks which returned IP to use, Route 53 is not balancing the connections itself. ```text Records checked: A (healthy), B (healthy), C (unhealthy) Route 53 returns: A and B only Client picks one and connects ``` > 🔴 **Common Mistake:** Treating Multi-Value routing as a substitute for an actual load balancer. It improves availability by excluding unhealthy endpoints from DNS answers, but the client - not AWS - decides which of the returned IPs to actually use, and there is no traffic-shaping or connection draining involved. ---
### The problem a CDN solves An origin server in Mumbai serves a user in Sao Paulo. Every byte crosses continents on every request, and if ten thousand users hit the same static image simultaneously, the origin answers that identical request ten thousand times. **CloudFront** is AWS's CDN - it caches your content at edge locations distributed globally, so repeat requests from nearby users get served from the edge instead of crossing the world back to your origin. ```text Without CloudFront: User in Brazil -> Origin in Mumbai (slow, every request hits origin) With CloudFront: User in Brazil -> Edge Location in Sao Paulo (fast, cached, origin untouched after first hit) ``` The benefit is two-sided: users get lower latency, and your origin gets dramatically less traffic, because only cache misses ever reach it. ### The three kinds of origins CloudFront can sit in front of **S3 bucket** - for static files. The bucket stays fully private using **Origin Access Control (OAC)**, which replaces the older Origin Access Identity (OAI); only CloudFront can read from the bucket, and direct S3 URLs return Access Denied to everyone else. **VPC Origin** - for an application living in a private subnet (private ALB, private NLB, or private EC2 instances). CloudFront reaches in over the private AWS network, so nothing in your VPC needs a public IP at all. **Custom Origin (HTTP)** - any public HTTP backend: a public ALB, an S3 static website endpoint, or an on-premises server. ```text S3 origin: Users -> CloudFront Edge -> (private, via OAC) -> S3 (private) VPC origin: Users -> CloudFront Edge -> VPC Origin -> Private ALB/EC2 Custom origin: Users -> CloudFront Edge -> Public HTTP backend ``` > 💡 **Tip:** If a design requirement says "no public exposure" or "most secure," the answer is VPC Origins for an application backend, or OAC for an S3 backend - never a public IP locked down after the fact by security group rules alone. ### Cache behaviors - routing different paths differently A CloudFront distribution is not one monolithic cache setting - **cache behaviors** let you apply different rules to different URL path patterns within the same distribution. ```text Distribution: app.zomato-clone.com Behavior: /static/* -> Origin: S3 bucket -> Cache TTL: 24 hours (images, CSS, JS rarely change) Behavior: /api/* -> Origin: ALB -> Cache TTL: 0 (dynamic data, always go to origin) Behavior: Default (*) -> Origin: ALB -> Cache TTL: short default ``` Each behavior can point at a different origin, use a different cache policy, and forward a different set of headers, cookies, and query strings - which matters because forwarding more of those to the origin generally means more cache misses, since CloudFront treats requests with different headers or query strings as different cache keys. > 🔴 **Common Mistake:** Forwarding all cookies and headers to origin "just in case" on a behavior meant to cache static content. Every distinct cookie value becomes part of the cache key, which fragments the cache into many near-duplicate entries and quietly turns a cacheable path into one that almost never hits cache. ### Cache invalidation - forcing a refresh before TTL expires Updating a file in S3 does not update what CloudFront is already holding at the edge - old content keeps serving until the TTL expires, which could be hours. ```text You update index.html in S3 -> Edge locations still serve the old cached version -> Users see stale content until TTL expires You trigger a Cache Invalidation on /index.html -> CloudFront clears that path from cache at every edge -> Next request -> cache miss -> fresh fetch from origin ``` Invalidation paths can be a specific file (`/index.html`), a folder (`/images/*`), or everything (`/*`) - though a full wildcard invalidation is the most expensive option and briefly increases origin load as every cached object is fetched fresh again. > 🔴 **Common Mistake:** Updating content in the origin and assuming users see it instantly. Without an explicit invalidation, users keep seeing the cached version until TTL naturally expires - always invalidate the specific changed paths after a content update. ### Lambda@Edge versus CloudFront Functions Both let you run code at the edge to modify requests or responses without a round trip to origin, but they are built for different weights of logic. | | CloudFront Functions | Lambda@Edge | |:---|:---|:---| | Language | JavaScript only | Node.js or Python | | Execution location | CloudFront edge locations (all of them) | A smaller set of CloudFront Regional Edge Caches | | Max execution time | Sub-millisecond, very short | Up to seconds, depending on trigger point | | Typical use | Header manipulation, simple redirects, URL rewrites, basic auth checks | Calling other AWS services, complex transformations, A/B testing logic | | Trigger points | Viewer request, viewer response | Viewer request/response, origin request/response | | Cost and scale profile | Cheaper, built for very high request volume | More capable, higher cost per invocation | > 📌 **Remember:** Start with CloudFront Functions for anything simple - a redirect, a header rewrite, a basic check. Reach for Lambda@Edge only when the logic genuinely needs more compute time or has to call out to another AWS service, since it costs more and runs at fewer edge locations. ---
The two questions every global-facing app has to answer A food delivery app built for Bengaluru launches in Dubai. Every...
What actually happens when you type a domain name Nobody types IP addresses. A user types zomato-clone.com and expects i...
The record types you actually use daily Every DNS record has a name, a type, a value, and (with one exception) a TTL. A ...
What a health check actually monitors A Route 53 Health Check continuously probes a resource and reports healthy or unhe...
Why one routing policy rarely covers a whole architecture Route 53 supports eight distinct routing policies, and picking...
The problem a CDN solves An origin server in Mumbai serves a user in Sao Paulo. Every byte crosses continents on every r...
ACM - certificates for HTTPS, with one region-specific catch AWS Certificate Manager (ACM) issues and manages the TLS ce...
They both use the AWS edge network, but solve different problems This distinction gets confused constantly because both ...
This lab wires together a Route 53 hosted zone, an ACM certificate, a CloudFront distribution in front of a private S3 b...
Routing policy decision guide: Need Policy Single resource, no failover needed Simple Canary release or percentage-based...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.