cerf
Static websites and media delivery

Static websites and media delivery

Global static site and media delivery with S3 and CloudFront

Store the bytes once in a private bucket, serve them everywhere from the edge, and never open the bucket to the internet.

The seam: storage origin versus edge delivery

This pattern splits along the same seam every global-delivery question does: where the bytes live versus where they are served. Amazon S3 is the origin. It durably holds every object (HTML, CSS, JavaScript, images, video segments) but is not built to be a low-latency front door for viewers scattered around the planet.

Amazon CloudFront is the delivery layer. It caches objects at edge locations close to viewers and answers their requests there. On a cache hit the edge serves the object directly with no trip back to the bucket; only on a cache miss does CloudFront fetch from the S3 origin, cache the result, and serve it. That is why the pattern scales globally: repeat requests for the same static asset are absorbed at the edge instead of hammering the origin.

The seam: S3 origin of record versus CloudFront edge delivery
The seam: S3 origin of record versus CloudFront edge deliveryAWS CloudCloudFront distribution — global edge networkS3 origin RegionHTTPS GET (nearest edge)HTTPS GET (nearest edge)HTTPS GET (nearest edge)cache misscache misscache missorigin fetch on missViewers —AmericasViewers —EuropeViewers — AsiaPacificEdge location(US)cache hit pathEdge location(EU)Edge location(APAC)Regional edgecachemid-tier cacheS3 originbucketdurable object store
Trace
Bytes live once in a durable S3 bucket; they are served everywhere from CloudFront's global edge network. Viewers hit the nearest edge location. A cache hit is answered right there with no origin trip. A cache miss walks up through the regional edge cache to the S3 origin, caching the result on the way back so the next request is a hit.

Locking the bucket to the distribution with OAC

The bucket stays private. S3 Block Public Access remains on, and no object is world-readable. Access is granted to exactly one caller: the CloudFront distribution. This is done with Origin Access Control (OAC), the current recommended mechanism and the successor to the legacy Origin Access Identity (OAI). With OAC, CloudFront signs each origin request with SigV4, and the S3 bucket policy allows GetObject only when the request comes from your distribution.

The result is a single front door. Viewers can only reach objects through CloudFront over HTTPS, never by hitting the S3 URL directly. This is the answer whenever a scenario says 'serve S3 content globally but the bucket must not be publicly accessible.'

Locking the private bucket to one caller with Origin Access Control
Locking the private bucket to one caller with Origin Access ControlAWS CloudCloudFront edgeS3 origin RegionHTTPS GET (only path in)signs requestSigV4 origin requestallow GetObject from distribution ARNblocks all public accessdecrypts objectsdirect request → 403 Access Deniedlogs GetObjectGlobal viewersHTTPS onlyCloudFrontdistributionOAC enabledOrigin AccessControlSigV4 signerS3 bucketpolicyGetObject from dist…Block PublicAccessON (account + bucke…S3 originbucketprivate, no public …SSE-KMS keyencryption at restDirect-to-S3requestbypass attemptCloudTrail dataeventsaudit S3 GetObject
Trace
The bucket stays private with S3 Block Public Access on and no world-readable objects. The only caller that can read it is the CloudFront distribution: OAC signs each origin request with SigV4, and the bucket policy allows GetObject only when the request carries the distribution's ARN. A direct hit on the S3 URL is denied. Objects are encrypted at rest with KMS and access is audited by CloudTrail.

HTTPS, custom domains, and the us-east-1 certificate rule

To serve the site on your own domain over TLS, you attach an alternate domain name (CNAME) to the distribution and an AWS Certificate Manager (ACM) certificate for that domain. There is one rule the exam loves: a certificate used by CloudFront must be requested or imported in the us-east-1 (N. Virginia) Region, no matter where the S3 bucket or the rest of the application lives, because CloudFront is a global service that reads its certificates from us-east-1.

Route 53 ties it together with an alias record that points the domain (including the zone apex) at the distribution. Set the viewer protocol policy to redirect HTTP to HTTPS so every request is encrypted at the edge.

Custom domain, Route 53 alias, and the us-east-1 certificate rule
Custom domain, Route 53 alias, and the us-east-1 certificate ruleAWS CloudRoute 53 hosted zone — example.comus-east-1 (N. Virginia)eu-west-1 (origin)1. DNS query www.example.comalias recordresolves to distribution2. HTTPS GET (TLS at edge)HTTP :80 → 301 redirect to HTTPS3. TLS certificate (from us-east-1)validates ownership4. origin fetch via OACViewer browserhttps://www.example…Route 53hosted zoneAlias A/AAAArecordapex + www → distri…ACMDNS-validation…proves domain owner…CloudFrontdistributionviewer protocol: re…ACM certificateMUST be in us-east-1HTTP request(:80)redirected to HTTPSS3 originbucketeu-west-1, private
Trace
A Route 53 alias record points the domain (including the zone apex) at the distribution. The distribution carries the alternate domain name (CNAME) and terminates TLS at the edge using an ACM certificate that MUST live in us-east-1, regardless of where the origin bucket sits (here eu-west-1). The viewer protocol policy 301-redirects any HTTP request to HTTPS so every request is encrypted.

Cache behaviors and invalidation for static versus media

One distribution can treat different paths differently through cache behaviors: a path pattern (for example /images/* or /video/*) maps to its own cache settings. Immutable, versioned assets get long time-to-live (TTL) values so they stay cached at the edge for a long time; frequently changing files get short TTLs.

When you deploy new content, you push the update in one of two ways: invalidate the affected paths so CloudFront drops the stale cached copies, or publish objects under new versioned file names (for example app.abc123.js) so viewers request a fresh URL. Versioned file names are the cheaper, more scalable choice because they avoid per-object invalidation entirely.

Cache behaviors by path pattern, and refreshing content on deploy
Cache behaviors by path pattern, and refreshing content on deployAWS CloudCache behaviors (path pattern → TTL)Content updatesS3 origin RegionHTTPS GET by path* match/static/* match/images/* match/video/* matchorigin fetch on missorigin fetch (rare, long TTL)origin fetch on missoption A: invalidate pathsoption B: publish new filenames (preferred)drop stale cacheupload new objectViewer requestGET /video/movie.m3…CloudFrontdistributionroutes by path patt…Defaultbehavior (*)short TTL/static/*behaviorTTL 1 year, immutab…/images/*behaviorlong TTL/video/*behaviorlong TTL, segmentsS3 originbucketsingle origin, many…Deployment /CI-CDships new contentPathinvalidatione.g. /index.htmlVersionedfilenamesapp.abc123.js
Trace
One distribution treats paths differently through cache behaviors: each path pattern maps to its own TTL. Immutable, versioned assets get long TTLs and almost always hit at the edge; frequently changing files get short TTLs. On deploy you either invalidate the changed paths (CloudFront drops the stale copies) or publish objects under new versioned filenames — the cheaper, more scalable choice, because a new URL guarantees a fresh fetch with no invalidation at all.

Private media with signed URLs and signed cookies

Not all media is public. For paid downloads, gated video, or member-only files, CloudFront restricts access with signed URLs and signed cookies. The origin bucket stays locked behind OAC as before; the difference is that the edge now also refuses to serve unless the viewer presents a valid signature.

The distinction the exam tests: use a signed URL to grant access to a single specific file, and use signed cookies to grant access to multiple restricted files (an entire video library or a group of assets) without generating a URL per object. Both let you set an expiry, so a link or session grants time-limited access.

Private media with signed URLs and signed cookies
Private media with signed URLs and signed cookiesTime-limited access grantAWS CloudApplication tierCloudFront distribution (restricted content)S3 origin Region1. sign in / entitlement checkauthorizedread CloudFront private key2a. issue signed URL (one file)2b. issue signed cookies (many files)single-file grantmulti-file grant3. GET media + signaturevalidates signature + expiry4. cache miss → sign origin requestSigV4 origin requestMember(browser)paid / gated accessSign-in / authverifies entitlementSigner backendissues the grantCloudFrontprivate keykept secretSigned URL→ ONE specific fileSigned cookies→ MANY restricted f…CloudFrontdistributionrestricted behaviorTrusted keygrouppublic keyOrigin AccessControlSigV4 signerS3 originbucketprivate, OAC-locked
Trace
Gated media keeps the origin locked behind OAC, but the edge now also refuses to serve without a valid signature. After authenticating the member, a signer backend uses the CloudFront private key to issue a grant: a signed URL for a single specific file, or signed cookies for many restricted files (a whole library) without a URL per object. Both carry an expiry. The edge validates the signature against a trusted key group before fetching the still-private object via OAC.

Sources

Practice what you just read

6 questions from this architecture

Loading…