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-https forces all requests to use HTTPS.
    • AllowedMethods and CachedMethods specify which HTTP methods CloudFront should accept and cache.
    • ForwardedValues (now CachePolicyId or OriginRequestPolicyId in newer configurations, but ForwardedValues is still widely used and understood) controls what parts of the request (query strings, cookies, headers) are forwarded to the origin and affect caching. Setting QueryString: 'false' and Cookies: { Forward: none } means identical URLs with different query strings or cookies will hit the same cache entry, maximizing cache hits.
    • MinTTL, DefaultTTL, MaxTTL control how long CloudFront caches objects at the edge locations. DefaultTTL: 3600 means 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_100 is 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.

Want structured learning?

Take the full Cloudformation course →