AWS CloudFront doesn’t just cache your content closer to users; it actively rewrites HTTP headers to optimize delivery and security, often in ways you wouldn’t expect.
Let’s get a CloudFront distribution up and running from the ground up. We’ll start with a simple S3 origin.
First, you need an S3 bucket to hold your static assets.
aws s3 mb s3://my-awesome-static-site-12345 --region us-east-1
Now, let’s upload a sample index.html file.
echo "<h1>Hello from CloudFront!</h1>" > index.html
aws s3 cp index.html s3://my-awesome-static-site-12345/index.html
Next, we create the CloudFront distribution. This is where the magic starts. We’ll point it to our S3 bucket.
aws cloudfront create-distribution \
--distribution-config '{
"CallerReference": "my-static-site-setup-$(date +%s)",
"Comment": "Distribution for my static site",
"Enabled": true,
"Origins": {
"Quantity": 1,
"Items": [
{
"Id": "my-s3-origin",
"DomainName": "my-awesome-static-site-12345.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
}
]
},
"DefaultCacheBehavior": {
"TargetOriginId": "my-s3-origin",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": ["GET", "HEAD"],
"CacheModes": {
"Forward": "none"
}
},
"Compress": true,
"ForwardedValues": {
"QueryString": false,
"Cookies": {
"Forward": "none"
},
"Headers": {
"Quantity": 0
},
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88632e7e01"
},
"MinTTL": 0,
"DefaultTTL": 86400,
"MaxTTL": 31536000
},
"CacheBehaviors": {
"Quantity": 0
},
"CustomErrorResponses": {
"Quantity": 0
},
"PriceClass": "PriceClass_100",
"Aliases": {
"Quantity": 0,
"Items": []
},
"DefaultRootObject": "index.html",
"HttpVersion": "http2",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": true,
"SSLSupportMethod": "sni-only"
}
}'
This command creates a distribution. It takes a few minutes to deploy. The CallerReference is a unique identifier for this request, helpful for idempotency. Enabled: true means it’s active on deployment.
The Origins section tells CloudFront where to fetch content. Here, DomainName is your S3 bucket’s endpoint. For now, we’re not using an Origin Access Identity (OAI), meaning the bucket is publicly readable. We’ll fix that later for better security.
DefaultCacheBehavior is crucial.
ViewerProtocolPolicy: "redirect-to-https"forces users to use HTTPS.AllowedMethodsspecifies which HTTP verbs CloudFront will allow.GETandHEADare typical for static content.Compress: truetells CloudFront to compress files (like Gzip) if the viewer supports it, saving bandwidth.ForwardedValuescontrols what CloudFront passes to the origin and how it caches.QueryString: falseandCookies: {Forward: "none"}mean these won’t be part of the cache key, so?v=1and?v=2will hit the same cache entry. TheCachePolicyId658327ea-f89d-4fab-a63d-7e88632e7e01is the "Managed-CachingOptimized" policy, which is a good default for static assets.MinTTL,DefaultTTL,MaxTTLdefine how long CloudFront caches objects at the edge.86400seconds is one day.
DefaultRootObject: "index.html" ensures that when a user requests /, they get your index.html file. HttpVersion: "http2" enables HTTP/2 for faster connections.
Once deployed, you’ll get a distribution ID and a domain name like d123abcdefghijk.cloudfront.net. You can then access your index.html via https://d123abcdefghijk.cloudfront.net/.
Now, let’s secure that S3 bucket. You don’t want your origin publicly accessible. We’ll create an Origin Access Identity (OAI) and grant it permissions to your S3 bucket.
First, get the OAI ID from your distribution’s configuration. You can find this in the AWS Console under your distribution’s "Origins" tab, or by describing the distribution:
aws cloudfront get-distribution --id YOUR_DISTRIBUTION_ID --query 'Distribution.Origins.Items[0].S3OriginConfig.OriginAccessIdentity' --output text
This will give you something like origin-access-identity/cloudfront/E123ABCDEFGH.
Now, create a bucket policy that only allows the OAI to s3:GetObject.
aws s3api put-bucket-policy \
--bucket my-awesome-static-site-12345 \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GrantCloudFrontAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E123ABCDEFGH"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-awesome-static-site-12345/*"
}
]
}'
Replace E123ABCDEFGH with your actual OAI identifier.
Finally, update your CloudFront distribution to use this OAI. This involves modifying the origin configuration.
aws cloudfront update-distribution \
--id YOUR_DISTRIBUTION_ID \
--if-match YOUR_ETAG_VALUE \
--distribution-config '{
"CallerReference": "my-static-site-update-$(date +%s)",
"Comment": "Distribution for my static site with OAI",
"Enabled": true,
"Origins": {
"Quantity": 1,
"Items": [
{
"Id": "my-s3-origin",
"DomainName": "my-awesome-static-site-12345.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": "origin-access-identity/cloudfront/E123ABCDEFGH"
}
}
]
},
"DefaultCacheBehavior": {
"TargetOriginId": "my-s3-origin",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": ["GET", "HEAD"],
"CacheModes": {
"Forward": "none"
}
},
"Compress": true,
"ForwardedValues": {
"QueryString": false,
"Cookies": {
"Forward": "none"
},
"Headers": {
"Quantity": 0
},
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88632e7e01"
},
"MinTTL": 0,
"DefaultTTL": 86400,
"MaxTTL": 31536000
},
"CacheBehaviors": {
"Quantity": 0
},
"CustomErrorResponses": {
"Quantity": 0
},
"PriceClass": "PriceClass_100",
"Aliases": {
"Quantity": 0,
"Items": []
},
"DefaultRootObject": "index.html",
"HttpVersion": "http2",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": true,
"SSLSupportMethod": "sni-only"
}
}'
You need to replace YOUR_DISTRIBUTION_ID and YOUR_ETAG_VALUE. The ETag is a version identifier for the distribution configuration, obtained by first describing the distribution.
One subtle but powerful aspect of CloudFront is its ability to manipulate HTTP headers. For example, you can configure CloudFront to add a Cache-Control header to your responses even if your origin doesn’t send one. This is done within the DefaultCacheBehavior or specific CacheBehaviors by setting ResponseHeadersPolicy. You can create custom policies or use managed ones like Managed-CORS-S3Origin. When you use these, CloudFront often adds headers like Access-Control-Allow-Origin or Content-Security-Policy based on the policy’s configuration, effectively enhancing security and cross-origin resource sharing capabilities without touching your S3 bucket.
The next step is often integrating with a custom domain name using Route 53 and an SSL certificate from ACM.