CloudFront distributions don’t actually serve content themselves; they’re just sophisticated DNS resolvers that proxy requests to origin servers.
Let’s see one in action. Imagine you want to serve static assets from an S3 bucket with a custom domain name and SSL. Here’s a CloudFormation snippet that makes it happen:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFront distribution for S3 static assets
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-unique-static-assets-bucket-12345 # Must be globally unique
AccessControl: Private # Content should only be served via CloudFront
MyCloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: OAI for my-static-assets-bucket
MyCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt MyS3Bucket.RegionalDomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${MyCloudFrontOriginAccessIdentity}"
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
Headers: []
MinTTL: 0
DefaultTTL: 3600 # Cache for 1 hour
MaxTTL: 86400 # Max cache for 1 day
Enabled: 'true'
Comment: Distribution for my-static-assets-bucket
Aliases:
- static.mydomain.com # Your custom domain
DefaultRootObject: index.html
PriceClass: PriceClass_100 # US and Europe only for cost savings
Outputs:
CloudFrontDomainName:
Description: The domain name of the CloudFront distribution
Value: !GetAtt MyCloudFrontDistribution.DomainName
CloudFrontDistributionId:
Description: The ID of the CloudFront distribution
Value: !Ref MyCloudFrontDistribution
This template sets up an S3 bucket, an Origin Access Identity (OAI) to grant CloudFront read access to the bucket, and the CloudFront distribution itself. The DistributionConfig is where the magic happens:
- Origins: Defines where CloudFront fetches content. Here, it’s our S3 bucket, and we use the OAI to ensure only CloudFront can access it directly.
- DefaultCacheBehavior: This is the core of CloudFront’s performance. It dictates how requests are handled.
ViewerProtocolPolicy: redirect-to-httpsforces all requests to use HTTPS.AllowedMethodsandCachedMethodsspecify which HTTP methods CloudFront should accept and cache.ForwardedValues(nowCachePolicyIdorOriginRequestPolicyIdin newer configurations, butForwardedValuesis still widely used and understood) controls what parts of the request (query strings, cookies, headers) are forwarded to the origin and affect caching. SettingQueryString: 'false'andCookies: { Forward: none }means identical URLs with different query strings or cookies will hit the same cache entry, maximizing cache hits.MinTTL,DefaultTTL,MaxTTLcontrol how long CloudFront caches objects at the edge locations.DefaultTTL: 3600means objects will be cached for an hour by default if not otherwise specified.
- Enabled: 'true' activates the distribution.
- Aliases: Your custom domain name (e.g.,
static.mydomain.com). You’ll need to set up a CNAME record in your DNS pointing this to the CloudFront distribution’s domain name. - DefaultRootObject: The file CloudFront serves when a user requests the root of your domain (e.g.,
index.html). - PriceClass: Determines which AWS edge locations your distribution serves content from, impacting performance and cost.
PriceClass_100is the most cost-effective, serving only North America and Europe.
When a user requests static.mydomain.com/image.jpg, their DNS request is resolved by CloudFront. If the content isn’t in the nearest edge location’s cache, CloudFront uses the OAI to fetch image.jpg from your S3 bucket, caches it according to the TTLs, and then serves it to the user. Subsequent requests for the same object from users in that region will be served directly from the edge cache.
What most people miss is how granularly you can control cache behavior per path using CacheBehaviors (plural) within DistributionConfig, in addition to the DefaultCacheBehavior. You can set different TTLs, forward different headers/cookies/query strings, or even point to different origins based on URL patterns. For example, you could cache static assets aggressively (DefaultTTL: 3600) but bypass the cache entirely for API requests (PathPattern: /api/*, ForwardedValues: { QueryString: 'true', Cookies: { Forward: all } }, DefaultTTL: 0).
The next thing you’ll likely grapple with is invalidating cached content when you update your origin files.