iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

CloudFront

CloudFront is AWS’s global CDN. Caches origin responses at 600+ edge locations, terminates TLS, runs functions at the edge. Origin = S3, ALB, custom HTTP backend, or another CloudFront distribution.

Create, cache, OAC, functions, invalidate

EXAMPLE
# 1) Create a distribution (Console / CLI / IaC)
aws cloudfront create-distribution --distribution-config file://dist-config.json

# dist-config.json (abbreviated)
{
    "CallerReference": "unique-string",
    "Comment":         "app.example.com",
    "Enabled":         true,
    "DefaultRootObject": "index.html",
    "PriceClass":      "PriceClass_100",      // 100 = NA + EU; All = global; cheapest first
    "Origins": {
        "Quantity": 1,
        "Items": [{
            "Id":           "s3-origin",
            "DomainName":   "my-bucket.s3.us-east-1.amazonaws.com",
            "S3OriginConfig": { "OriginAccessIdentity": "" }
        }]
    },
    "DefaultCacheBehavior": {
        "TargetOriginId":       "s3-origin",
        "ViewerProtocolPolicy": "redirect-to-https",
        "AllowedMethods":       { "Quantity": 2, "Items": ["GET","HEAD"] },
        "CachePolicyId":        "658327ea-f89d-4fab-a63d-7e88639e58f6",  // Managed-CachingOptimized
        "Compress":             true
    },
    "ViewerCertificate": { "CloudFrontDefaultCertificate": true }
}

# 2) Custom domain (Route53 → CloudFront)
# 1. Issue ACM cert in us-east-1 (CloudFront only reads from us-east-1)
# 2. Add Alternate Domain Name (CNAME) on the distribution
# 3. Set ViewerCertificate to use that cert
# 4. Route53: A record alias → d111111.cloudfront.net

# 3) Origin Access Control (OAC) — secure S3 origin
# Replaces Origin Access Identity (OAI — legacy).
# 1. Create OAC; 2. Attach to distribution; 3. Update S3 bucket policy

{
    "Version": "2012-10-17",
    "Statement": [{
        "Sid":      "AllowCloudFrontReadOnly",
        "Effect":   "Allow",
        "Principal": { "Service": "cloudfront.amazonaws.com" },
        "Action":   "s3:GetObject",
        "Resource": "arn:aws:s3:::my-bucket/*",
        "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1ABCDEF"
            }
        }
    }]
}
# Block all public access on the bucket. Only CloudFront can read it.

# 4) Cache behaviour patterns
#
# Static assets (long TTL, immutable filenames):
#   Cache-Control: public, max-age=31536000, immutable
#   /assets/main.<hash>.js     → cache 1 year
#
# HTML / API (short TTL):
#   Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60
#   /index.html                → cache 60s, refresh in background
#
# Personalised (no caching):
#   Cache-Control: no-store
#   /api/me                    → never cached at the edge

# 5) Managed cache policies (preferred over Legacy)
#   CachingOptimized            : default; caches by URL
#   CachingDisabled             : never cache
#   CachingOptimizedForUncompressedObjects : pre-compressed origins
#   Elemental-MediaPackage      : streaming
#   Amplify                     : SPA defaults

# 6) Origin request policy
# Decides which headers / cookies / query strings get forwarded to the origin.
# Use 'AllViewer' if origin needs everything; 'UserAgentRefererHeaders' for selective.

# 7) Invalidate the cache (push updates immediately)
aws cloudfront create-invalidation \
    --distribution-id E1ABCDEF \
    --paths '/index.html' '/assets/styles.css'

# Wildcards
aws cloudfront create-invalidation --distribution-id E1ABCDEF --paths '/*'

# Cost: first 1000 path invalidations / month free; $0.005 each after.
# Better: hash filenames + long max-age so you NEVER need to invalidate /assets/*.

# 8) CloudFront Functions — JS at the edge (cheap, fast, limited)
# Use case: header rewrites, A/B routing, simple URL rewrites, redirect insertion
# Limit: 1 ms CPU, 2 MB memory, no network access

function handler(event) {
    const request = event.request;
    // Add canonical headers
    request.headers['x-canonical-host'] = { value: 'app.example.com' };

    // Pretty URLs (e.g. /about → /about/index.html)
    if (request.uri.endsWith('/')) {
        request.uri += 'index.html';
    } else if (!request.uri.includes('.')) {
        request.uri += '/index.html';
    }
    return request;
}

# 9) Lambda@Edge — Node.js / Python at the edge (slower, more capable)
# Use case: auth, A/B testing with origin lookups, image manipulation, SSR for SEO
# Limit: 5 sec CPU, 128 MB memory, can call other AWS APIs

export const handler = async (event) => {
    const req = event.Records[0].cf.request;
    // Auth gate
    const auth = req.headers.authorization?.[0]?.value;
    if (!auth || !await verifyToken(auth)) {
        return {
            status: '401',
            statusDescription: 'Unauthorized',
            body: JSON.stringify({ error: 'unauthorised' }),
        };
    }
    return req;
};

# 10) Geographic restrictions / WAF
# CloudFront supports country-level allow / deny lists.
# For richer rules (bots, rate limits, IP reputation), attach AWS WAF.

# 11) Signed URLs / cookies — private content delivery
import { getSignedUrl } from '@aws-sdk/cloudfront-signer';

const url = getSignedUrl({
    url: 'https://app.example.com/private/file.pdf',
    keyPairId: 'KEYPAIRIDXXX',
    privateKey: fs.readFileSync('./cf-private-key.pem', 'utf8'),
    dateLessThan: new Date(Date.now() + 5 * 60_000).toISOString(),    // 5 min
});
# Use for: paywalled assets, time-limited downloads, private S3 content over CloudFront.

# 12) Logs
# Standard logs → S3 (5-min lag). Real-time logs → Kinesis (sub-second).
aws cloudfront update-distribution --id E1ABCDEF --distribution-config '{
    "Logging": {
        "Bucket": "my-cf-logs.s3.amazonaws.com",
        "Prefix": "app/",
        "IncludeCookies": false,
        "Enabled": true
    }
}'
# Combine with Athena to query.

# 13) Cost levers
# - PriceClass — restrict edge locations to NA+EU (cheapest) if your users are concentrated
# - Compression — enable; cuts bytes-out by ~70% for text
# - Long max-age + hashed filenames — minimise origin requests + invalidations
# - HTTP/2 + 3 — set-and-forget speed boost
# - Avoid invalidations; use cache busting via filenames
# - CloudFront Functions for header tweaks (cheaper than Lambda@Edge)

# 14) Common patterns
# Static site (SPA)             : S3 origin + OAC + CachingOptimized + cf-function for /index.html
# API + cache                   : ALB origin + custom cache policy by URL + Vary on Authorization
# Image resizer                 : Lambda@Edge resizes on origin response + caches result
# Multi-region failover         : Origin Group with primary + secondary
# Streaming                     : Elemental MediaPackage origin + CachingDisabled on manifests

# 15) Anti-patterns
#   ❌ Cache-Control: no-cache on everything → CDN useless
#   ❌ Invalidate /* on every deploy → use hashed filenames instead
#   ❌ S3 bucket public + CloudFront → defeats the security benefit; use OAC
#   ❌ Forwarding all headers to origin → defeats caching
#   ❌ TLS cert in wrong region (must be us-east-1)
#   ❌ Lambda@Edge for header tweaks (use CloudFront Functions; 10x cheaper)

# 16) Observability
# CloudWatch metrics: Requests, TotalErrorRate, BytesDownloaded, OriginLatency
# Real-time dashboards via Real User Monitoring (RUM)
# Alarms on CacheHitRate dropping (origin pressure)

Why it matters

CloudFront + OAC + S3 origin + hashed-filename caching is the cheap-and-fast modern static-site stack. Add CloudFront Functions for header tweaks, Lambda@Edge for anything heavier — never invalidate on every deploy.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# Global CDN — caches at hundreds of edge POPs.
Try it Yourself »

Discussion

Loading…