2 minutes
Speeding Up an S3 Website with CloudFront
What CloudFront will do for us
CloudFront addresses challenges such as reducing latency, distributing traffic globally through edge locations, caching content for repeat requests, and providing HTTPS/security for static websites on S3. This leads to faster page load times, reduced load on S3, and cost savings on traffic.
Site Performance Before Implementation
I wanted to check how much faster the site would become after implementing CloudFront. I measured the “before” results using DebugBear.

SSL Certificate
First, we need to issue an SSL certificate. In AWS Certificate Manager, request a free certificate for your domain, making sure to use the us-east-1 region. Validate it via DNS in Route 53 by adding the provided CNAME records.
CloudFront
Let’s go to the CloudFront console and create a distribution.

Origin: use the S3 website endpoint. SSL certificate — select the certificate created in the previous step (if it’s not there, it was likely created in the wrong region).

Wait for it to deploy, then go into the created distribution and click “Route Domain to CloudFront”.

The site should now be accessible via HTTPS and take advantage of CloudFront’s benefits.
Site Performance After Implementation
As we can see, the TTFB (Time to First Byte) has significantly decreased for most locations, which is exactly what we wanted to achieve.

Updating the Deploy Process
After deployment, the cache needs to be invalidated, which can be done from Github Actions.
Expanding User Permissions
For deployment, we created a user and attached a policy that describes what the user can do. First, we need to allow the user to invalidate the cache. Go to IAM -> Policies and edit the created policy so it looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::your-domain.com",
"arn:aws:s3:::your-domain.com/*"
]
},
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::YOUR-ACCOUNT:distribution/YOUR-DISTRIBUTION-ID"
}
]
}
Invalidating the Cache During Deployment
Add a line to .github/workflows/deploy.yml, making sure to substitute your own data. The file should now look something like this:
name: Deploy to S3
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: peaceiris/actions-hugo@v3
with:
hugo-version: '0.154.0'
extended: true
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
- run: hugo --minify
- run: aws s3 sync public/ s3://your-bucket --delete
- run: aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"
Now, after each deployment, the CloudFront cache will be invalidated.