Skip to content
Ganeswar Velvadapu

Deployment using AWS S3 and CloudFront

A simple walkthrough of hosting static web applications using AWS S3 and CloudFront.

AWS 2 min read

Over time I have deployed a fair number of applications, some frontend-only and some full stack. The approaches I used most often were:

  • Vercel for frontend, Render for backend
  • Vercel for both frontend and backend
  • Vercel for frontend, backend running on a server via Docker, systemd, or tmux
  • Both frontend and backend deployed on a single server

After going through these repeatedly, I wanted to try something different. That is when I came across static website hosting on AWS S3.

The setup is straightforward. Open the AWS console, go to S3, and create a bucket. Once the bucket is created, navigate to the Properties tab and scroll to the bottom. There you will find Static website hosting. Enable it.

Upload your build files into the bucket. For React or Next.js projects, this is typically the dist or out directory.

Next, unblock public access for the bucket so that users can reach the website. Then attach the following bucket policy:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}

Save the policy and your website URL will appear in the same static hosting section.

The problem with the setup above is that the S3 bucket is fully public, which is not ideal. CloudFront solves this.

CloudFront is a Content Delivery Network (CDN) — a system of servers distributed across the globe that delivers web content to users based on their geographic location. Instead of every request hitting a single origin server, a CDN serves cached copies of your content from the nearest location.

For this use case, CloudFront can be configured to access a private S3 bucket, so the bucket itself does not need to be public.

Start by making the S3 bucket private. Remove the public access settings and delete the bucket policy added earlier.

Then create a CloudFront distribution with the following configuration:

  • Price class: Free tier is available, so select that if cost is a concern.
  • Origin type: S3.
  • Origin: Select your S3 bucket.
  • Origin path: Leave this empty if index.html is at the root of the bucket. If it is under a subdirectory, enter that path here — for example, /dist.
  • S3 bucket access: Enable this option to allow CloudFront to access the private bucket. AWS will automatically create an Origin Access Control (OAC) policy and update the bucket policy.
  • Web Application Firewall: If you have the budget, enabling WAF lets you add rate limiting, geo-blocking, bot protection, and custom security rules. Otherwise, the default settings work fine.

After the distribution is created, open it and set the Default root object to index.html. This tells CloudFront what to serve when someone visits the root URL.

Save the changes and wait for the distribution to deploy.

Your site will be available at a URL like d17qc3sxzc8u5l.cloudfront.net. If you have a custom domain, add this as a CNAME record with your DNS provider and it will work as expected.


Next, try adding a dynamic website and see how it all comes together.

That’s it for this one, hope it helps!