Resources required to deploy a SPA

Prerequisites

Before you start, make sure that you have IAM User with admin privileges and Remote Backend (How to create Remote Backend with S3 and DynamoDB with Terraform) for Terraform setup.

Terraform folder structure

Usually, you will want to create multiple environments for the app, and you will use more than one resource at the same time. To make sure that you cover all these cases, you should have this kind of folder structure. This allows you to run terraform apply for each environment with different settings.

build/  
	- modules/  
		- webapp/  
			- cert.tf  
			- dns.tf  
			- s3.tf  
			- cloudfront.tf  
			- route53.tf  
			- variables.tf  
	- env/  
		- dev/  
			- main.tf  
		- prod  
			- main.tf		  

Step 1 (optional): Setup your remote backend

First thing first, create build folder within your project and within your main.tf file, where you will run modules. Inside of that main.tf, add the following

terraform {  
	backend "s3" {  
		encrypt = true  
		bucket = "bucket_name_where_you_store_state"  
		dynamodb_table = "dynamodb_for_locking_state"  
		region = "eu-west-2" <- region where your backend dynamodb is deployed  
		key = "key_within_dynamo/dev/terraform.tfstate" <- just use repo name as a key  
	}  
}  

Step 2: Setup your S3 bucket for an app

To setup S3 bucket, you have to setup the following:

Step 3: AWS Certificate Manager

Before you proceed, you have to create a certificate as it may take awhile to create it. For this, you need a domain as you can (but don’t have to) use a DNS to validate it.
https://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/list

Example

resource "aws_acm_certificate" "cert" {  
  domain_name       = var.domain  
  validation_method = "DNS"  
}  
  
  
resource "aws_route53_record" "cert" {  
  for_each = {  
    for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {  
      name   = dvo.resource_record_name  
      record = dvo.resource_record_value  
      type   = dvo.resource_record_type  
    }  
  }  
  
  allow_overwrite = true  
  name            = each.value.name  
  records         = [each.value.record]  
  ttl             = 60  
  type            = each.value.type  
  zone_id         = local.dns_zone_id  
}  
  
  
resource "aws_acm_certificate_validation" "cert" {  
  depends_on = [aws_acm_certificate.cert, aws_route53_record.cert]  
  
  certificate_arn         = aws_acm_certificate.cert.arn  
  validation_record_fqdns = [for record in aws_route53_record.cert : record.fqdn]  
}  

Step 4: Setup CloudFront

To setup CloudFront CDN, you have to do the following:

  • create CloudFront distribution with an origin id
  • (optional) add domains
  • enable ipv6
  • price class to tell Cloudfront where it should be distributed
  • add cache behaviour
    • allowed, cached methods, viewer protocol policy and cache policy for origin requests and cache policy
  • viewer certificate for your domain (the one that was created in step 3)
  • custom error response (for 403 and 404) so it knows that it should respond with 200 and redirect to index.html
  • (optional) restrictions, if there are any
    Example of CloudFront for S3 with Static Website

Once all of it is deployed, you should have an app that is cheap to run and distributed across the world