complete.systems logo

How to Host a Single Page Application (SPA) on AWS S3 and Serve It via CloudFront

A practical guide to hosting a Single Page Application on AWS S3 and serving it through CloudFront with proper client-side routing.

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.

For this we will use a simple React template.

AWS side will be configured with Terraform:

  • CloudFront distribution and function
  • S3 bucket

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, routing is handled on the client side. When a user visits /home, they are not loading a real file. Instead, index.html must be served and JavaScript takes over.

When hosting a SPA on S3 and opening example.com/home, S3 tries to find an object at /home. Because it doesn’t exist, S3 returns a 403 error.

Why We Need a CloudFront Function

To make this architecture behave like a proper web server, we attach a CloudFront Function to the Viewer Request phase.

The function inspects the request path and rewrites it to /index.html if it is a SPA route.

CloudFront Function Example

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 before first content is loaded
  • Global availability with low latency
  • Low cost compared to server-side hosting

AWS Infrastructure with Terraform

S3 Bucket Setup

  • Create S3 bucket
  • Block public access
  • Enable server-side encryption

CloudFront Function

  • Save function as single_page_application_handler.js
  • Create CloudFront Function

CloudFront Origin Access Control (OAC)

OAC provides secure access from CloudFront to S3.

CloudFront Distribution

Create distribution and attach function and OAC.

S3 Bucket Policy

Allow only CloudFront to access S3 objects.

Deploying the React Application

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

Upload build files:

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

Final Result

Your SPA is now hosted on S3 and delivered globally through CloudFront with proper client-side routing support.

Original article: https://medium.com/@mategogiberidze_14538/how-to-host-a-single-page-application-spa-on-aws-s3-and-serve-it-via-cloudfront-77a9d69e9ea5