Skip to content

Deployment of Single Page Application on AWS: S3, CloudFront, and Route53

Written by:

Igor Gorovyy
DevOps Engineer Lead & Senior Solutions Architect
LinkedIn

Using terraform for prepare infrastructure for single page application on aws

Table of Contents

  1. Architecture Overview
  2. S3 Configuration
  3. ACM Configuration
  4. CloudFront Configuration
  5. Route53 Configuration
  6. Key Integration Points
  7. Deployment Verification

GitHub Source Code: https://github.com/igorgorovoy/spa-app-aws.git

1. Architecture Overview

While preparing for the AWS Solutions Architect exam, I decided to take a deep dive into deploying a Single Page Application (SPA) on AWS. This article is a result of my research and hands-on experience setting up a scalable, secure, and cost-effective architecture. If you're looking for a structured way to host your SPA using AWS services, you're in the right place!

To deploy a Single Page Application (SPA), I used the following AWS services:
- S3: Stores static files (HTML, CSS, JS)
- CloudFront: CDN for fast content delivery
- Route53: DNS management
- ACM: SSL/TLS certificates

Architecture Diagram

graph TD;
    A[User] -->|DNS Request| B[Route 53]
    B -->|Alias Record| C[CloudFront CDN]
    C -->|HTTPS Request| D[ACM - SSL Certificate]
    C -->|Origin Request| E[S3 - Static Website Hosting]
    C -->|Caching| F[CloudFront Cache]

2. S3 Configuration

2.1. Creating an S3 Bucket via AWS Console:

  1. Go to: AWS Console → S3
  2. Create a new bucket
  3. Name: spa-app-aws.example.com
  4. Block all public access

Terraform code:

resource "aws_s3_bucket" "main" {
  bucket = "spa-app-aws.example.com"
}

resource "aws_s3_bucket_public_access_block" "main" {
  bucket = aws_s3_bucket.main.id
  block_public_acls   = true
  block_public_policy = true
  ignore_public_acls  = true
  restrict_public_buckets = true
}

2.2. Enabling Static Website Hosting:

resource "aws_s3_bucket_website_configuration" "static_site" {
  bucket = aws_s3_bucket.main.id
  index_document {
    suffix = "index.html"
  }
  error_document {
    key = "index.html" # Redirect all 404 errors to index.html for SPA
  }
}

3. ACM Configuration

3.1. Creating an SSL Certificate

One key takeaway from my exam preparation was that CloudFront requires SSL/TLS certificates from AWS Certificate Manager (ACM) in the us-east-1 region. This can be a common pitfall if not configured correctly.

Via AWS Console: 1. AWS Console → Certificate Manager 2. Request a certificate 3. Specify domains: example.com and *.example.com

Terraform code:

resource "aws_acm_certificate" "main" {
  provider = aws.us-east-1
  domain_name = "example.com"
  subject_alternative_names = ["*.example.com"]
  validation_method = "DNS"
  lifecycle {
    create_before_destroy = true
  }
}

4. CloudFront Configuration

4.1. Creating a CloudFront Distribution:

Setting up CloudFront properly was a crucial part of my learning experience. I had to ensure that all requests were routed correctly and that error handling was configured to support SPA routing.

resource "aws_cloudfront_distribution" "main" {
  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"
  aliases            = ["example.com"]
}

5. Route53 Configuration

5.1. Creating DNS Records:

Finally, linking everything together with Route 53 was a satisfying step, as it provided the final touch for ensuring smooth domain resolution.

resource "aws_route53_record" "main" {
  zone_id = "YOUR_ZONE_ID"
  name    = "example.com"
  type    = "A"
  alias {
    name                   = aws_cloudfront_distribution.main.domain_name
    zone_id                = aws_cloudfront_distribution.main.hosted_zone_id
    evaluate_target_health = false
  }
}

6. Key Integration Points

  • Origin Access Control (OAC) ensures secure access from CloudFront to S3.
  • Certificate must be in us-east-1 region for CloudFront integration.
  • Alias record in Route53 must point to the CloudFront distribution.

7. Deployment Verification

7.1. Upload Files

  • Upload all SPA files to the S3 bucket
  • Check file structure

7.2. Verify CloudFront

  • Wait for the CloudFront distribution to deploy (Status: Deployed)
  • Check availability via CloudFront URL

7.3. Check SSL

  • Ensure the certificate is active
  • Verify HTTPS connection

7.4. SPA Testing

  • Open the main URL
  • Test different SPA routes
  • Refresh pages on different routes

Additional Resources

Additional Considerations for Using Cloudflare Instead of Route 53

If you prefer to use Cloudflare for DNS management instead of Route 53, follow these additional steps:
1. Add your domain to Cloudflare and update your domain’s nameservers to Cloudflare’s provided ones.
2. Create a CNAME record in Cloudflare pointing your domain (e.g., example.com) to the CloudFront distribution domain.
3. Ensure SSL/TLS settings in Cloudflare are set to "Full" or "Full (Strict)" to maintain proper HTTPS connections.
4. Disable proxy mode (orange cloud) for the CNAME record to avoid conflicts with CloudFront.
5. Optionally, configure Page Rules in Cloudflare to optimize caching and performance for your SPA.

By following these steps, you can seamlessly integrate Cloudflare with your AWS-hosted SPA while benefiting from Cloudflare’s additional security and performance features.


By going through this hands-on experience, I feel much more confident in setting up a production-ready SPA architecture on AWS. If you're preparing for the Solutions Architect exam, I highly recommend practicing deployments like this to solidify your understanding. Happy learning!