DEV Community

Cover image for AWS Networking with Terraform: Hosting a static website using S3
Chinmay Tonape
Chinmay Tonape

Posted on • Edited on

AWS Networking with Terraform: Hosting a static website using S3

In our previous post, we leveraged AWS VPC Gateway Endpoint to establish secure connections to S3 over the AWS Private Network.

Continuing our journey into cloud, this installment will focus on harnessing the power of Amazon S3 for static website hosting. We will utilize Terraform to create modular components, streamlining the deployment process and ensuring scalability and maintainability.

You can use Amazon S3 to host a static website. On a static website, individual webpages include static content. They might also contain client-side scripts.

Architecture Overview:

Before we embark on the implementation, let's take a moment to understand the architecture we'll be working with:

S3 Static Website Architecture

Step 1: Create an S3 Bucket:

We'll begin by creating an S3 bucket with a unique name and configuring its public access settings and make it as static website.

####################################################
# S3 static website bucket
####################################################
resource "aws_s3_bucket" "my-static-website" {
  bucket = var.bucket_name
  tags = merge(local.common_tags, {
    Name = "${local.naming_prefix}-s3-bucket"
  })
}

####################################################
# S3 public access settings
####################################################
resource "aws_s3_bucket_public_access_block" "static_site_bucket_public_access" {
  bucket = aws_s3_bucket.my-static-website.id

  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

####################################################
# S3 bucket static website configuration
####################################################
resource "aws_s3_bucket_website_configuration" "static_site_bucket_website_config" {
  bucket = aws_s3_bucket.my-static-website.id

  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement Resource Policies:

To control access to our bucket and its contents, we'll establish resource policies. This could involve defining ownership controls using bucket and object ACLs or crafting resource policies.

####################################################
# S3 bucket policy
####################################################
resource "aws_s3_bucket_policy" "static_site_bucket_policy" {
  bucket = var.bucket_name

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "PublicReadGetObject"
        Principal = "*"
        Action = [
          "s3:GetObject",
        ]
        Effect = "Allow"
        Resource = [
          "arn:aws:s3:::${var.bucket_name}",
          "arn:aws:s3:::${var.bucket_name}/*"
        ]
      },
    ]
  })

  depends_on = [aws_s3_bucket_public_access_block.static_site_bucket_public_access]
}

Enter fullscreen mode Exit fullscreen mode

Instead of bucket resource policy, we can define bucket/object ACLs to define more granularity (code commented in github repo)

####################################################
# S3 bucket ownership controls and ACL (recommended if you want object level control).
####################################################
resource "aws_s3_bucket_ownership_controls" "static_site_bucket_ownership_controls" {
  bucket = aws_s3_bucket.my-static-website.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

resource "aws_s3_bucket_acl" "static_site_bucket_acl" {
  depends_on = [
    # aws_s3_bucket_ownership_controls.static_site_bucket_ownership_controls,
    aws_s3_bucket_public_access_block.static_site_bucket_public_access,
  ]

  bucket = aws_s3_bucket.my-static-website.id
  acl    = "public-read"
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Upload Website Files:

With our bucket configured, we'll upload the necessary files comprising our static website.

####################################################
# Upload files to S3 Bucket 
####################################################
resource "aws_s3_object" "provision_source_files" {
  bucket = aws_s3_bucket.my-static-website.id

  # webfiles/ is the Directory contains files to be uploaded to S3
  for_each = fileset("webfiles/", "**/*.*")

  key          = each.value
  source       = "webfiles/${each.value}"
  content_type = each.value
  #acl          = "public-read" #use this only if you are using Bucket and Object ACLs, defaults to private
}
Enter fullscreen mode Exit fullscreen mode

Steps to Run Terraform

Follow these steps to execute the Terraform configuration:

terraform init
terraform plan 
terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

Upon successful completion, Terraform will provide relevant outputs.

Apply complete! Resources: 7 added, 0 changed, 0 destroyed.

Outputs:

static_site_endpoint = "http://my-s3-static-bucket-v1.s3-website-us-east-1.amazonaws.com"
Enter fullscreen mode Exit fullscreen mode

Testing the outcome

S3 Bucket with objects:

S3 bucket with objects

Static website hosting enabled:

Static Website Settings

S3 Public Access Block:

S3 public access block

S3 Bucket Policy:

S3 Bucket Policy

A running website:

Website

Cleanup

Remember to stop AWS components to avoid large bills.

terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

Notes:

1) In this tutorial, the website was accessed using S3 Bucket Endpoint which will have name of the bucket, we can hide it by creating a CNAME record in Route53 if you have a domain.
2) We can either use bucket policy (used in majority of cases), but we can use bucket ownership controls and bucket/object ACLs to define more granularity. (Code is commented in main.tf, all objects also need to use acl="public-read")

We've successfully set up a static website hosting solution using Amazon S3.

In our next tutorial, we'll explore the integration of Content Delivery Networks (CDNs) to further optimize website performance and enhance user experience.

Resources:

Github Link: https://github.com/chinmayto/terraform-aws-s3-static-website
S3 Static Website: https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html

Top comments (0)