← Back to list

How to host a Single Page Application (SPA) on AWS S3 and serve it via CloudFront

Hosting modern web applications efficiently and securely is a common challenge in DevOps. In this post, we’ll walk through how to host a…

Mategogiberidze · 2025-07-01 08:47 · 0 claps · 2.8 min read
#single-page-applications #s3-bucket #cloudfront #terraform #cloudfront-functions
Open on Medium ↗
Wiki topics: 🌐 · Web Development ☁️ · DevOps & Cloud

How to host a Single Page Application (SPA) on AWS S3 and serve it via CloudFront

Hosting modern web applications efficiently and securely is a common challenge in DevOps. In this post, we’ll walk through how to host a Single Page Application (SPA) on AWS S3 and serve it via CloudFront.

We’re sharing this guide based on how we’ve deployed SPAs in production for real teams — minimal fluff, just practical steps.

This post is ideal for DevOps/Cloud engineers or developers looking to set up reliable, scalable static hosting on AWS.

🎯 Goal

In this post, we’ll set up a production-ready static site hosting architecture using AWS S3 + CloudFront to serve a Single Page Application (SPA). For this we will use React simple template.

We’ll configure AWS side with terraform:

  • CloudFront distribution and function
  • S3 Bucket

First question before we start is, maybe, why do we need CloudFront (and CloudFront Function), and what are the benefits of this architecture?

  • Why S3 Alone Doesn’t Work for SPAs Like React?

S3 is an object storage, not a web server like NGINX or Apache. It serves files exactly as they exist — no routing logic.

In SPAs (e.g., built with React, Angular, Vue), routing is handled on the client side. So when a user visits example.com/home, they’re not loading a file at /home. Instead, the browser loads index.html, and JavaScript takes over from there.

  • What Happens with S3 Alone:

When you host a SPA on S3 and someone opens example.com/home. S3 tries to find an object at /home, which doesn’t exist, so it returns a 403 error. It doesn't know that /home is a client-side route and should load /index.html.

  • Why We Need a CloudFront Function?

To make this architecture work like a proper web server, we attach a CloudFront Function to the Viewer Request phase. This function inspects the requested path and rewrites it to /index.html if it's a SPA route.

How request work with CloudFront and CloudFront function

How request work with CloudFront and CloudFront function

  • Rewriting Logic

We apply a simple rule: If the path starts with / and doesn't contain a . (dot), then it's not a file request — it’s most likely a page route like /home or /blog.

So instead of looking for /home on S3 (which doesn’t exist), we rewrite the request to serve /index.html.

function handler(event) {
  var request = event.request;
  var uri = request.uri;

  if (uri.startsWith("/") && !uri.includes(".")) {
    request.uri = "/index.html";
  }

  return request;
}
  • **Benefits:
  • **Serverless architecture
  • Fewer layers to load the first content for the client
  • Global availability with low latency
  • Low cost compared to server-side hosting

AWS Infrastructure with Terraform

  • **S3 Bucket Setup
  • S3 Bucket Creation**
  • Block public access, we need to not access without CloudFront
  • Server-Side Encryption. This enforces encryption at rest for all objects stored in the bucket.

[embed]

Before CloudFront distribution creation we need CloudFront function and CloudFront Origin Access Control (OAC)

[embed]

  • CloudFront Origin Access Control (OAC)

OAC provides a secure way to access S3 origins to CloudFront

[embed]

Now everything is ready for CloudFront

  • CloudFront Distribution

[embed]

At this moment CloudFront does not have access to s3 files, we have to add bucket policy

  • S3 Bucket Policy

[embed]

AWS infrastructure is done — now it’s time to create the React application and upload the built files to the S3 bucket.

npx create-react-app spa-example
cd spa-example
npm install
npm run build

This will generate a production-ready build of your app in the build/ directory.

We can upload files to s3 which client can render after visit our site

aws s3 sync build/ s3://single-page-application/

Your SPA is now hosted on S3 and delivered globally through CloudFront, with proper support for client-side routing using a lightweight CloudFront Function.

You can view the full source code and infrastructure setup in our GitHub project: 🔗 GitHub Repo — SPA Hosting with S3 + CloudFront

🔗 Useful Links

We hope this guide saved you some time or gave you ideas for improving your setup.


메타데이터
post_id
77a9d69e9ea5
slug
how-to-host-a-single-page-application-spa-on-aws-s3-and-serve-it-via-cloudfront-77a9d69e9ea5
url
https://medium.com/@mategogiberidze_14538/how-to-host-a-single-page-application-spa-on-aws-s3-and-serve-it-via-cloudfront-77a9d69e9ea5
canonical_url
https://medium.com/@mategogiberidze_14538/how-to-host-a-single-page-application-spa-on-aws-s3-and-serve-it-via-cloudfront-77a9d69e9ea5
author_url
https://medium.com/@mategogiberidze_14538
status
ok
fetched_at
2026-07-10 00:10:16