Terraform Cloud Project Bootcamp with Andrew Brown — Static Website Hosting

Quick preface

Gwen Leigh
4 min readSep 29, 2023

This article is part of my Terraform journey with Terraform Bootcamp by Andrew Brown and Andrew Bayko with Chris Williams and Shala.

My wild career adventure into Cloud Computing continues with Andrews, and I highly, highly recommend you to come join us if you are interested. Check out Andrews’ free youtube learning contents. You can also buy some paid courses here to support their good cause.

Agenda

This session is all about setting up the bucket!
  • ✅ 1) Add the Configuration for Static Website Hosting
  • ✅ 2) Declare module outputs and reference them from root
  • ✅ 3) Upload files using Terraform
  • ✅ 4) Detect data change in files with Terraform
  • ✅ 5) Troubleshoot — Missing required argument

1. Add the Configuration for Static Website Hosting

To enable static website hosting in S3 bucket using Terraform. we introduce the following code. You can refer to this TF documentation for detail.

  • ./modules/terrahouse_aws/main.tf
resource "aws_s3_bucket_website_configuration" "website_configuration" {
bucket = aws_s3_bucket.website_bucket.bucket

index_document {
suffix = "index.html"
}

error_document {
key = "error.html"
}

# routing_rule {
# condition {
# key_prefix_equals = "docs/"
# }
# redirect {
# replace_key_prefix_with = "documents/"
# }
# }
}

Then try running the following:

terraform plan  # for validation
terraform apply --auto-approve

Then go check your AWS console if the newly created S3 bucket has the static website hosting option enabled.

Click on Properties tab, scroll all the way down. Check if the option is correctly enabled.

2. Declare module outputs and reference them from root

/PROJECT_ROOT
├── /modules
| /terrahouse_aws
| ├── ...
| ├── outputs.tf
| └── ...
├── ...
├── outputs.tf
└── ...

Above is the simplified structure of our project highlighting the depths of the outputs.tf files. See how the output declaration at module and output referencing from root compare.

  • Output declaration: references the resource declared in the main.tf file inside the same module (resource entity).
  • Output referencing: specifies the path to the output of a module (file path).
# outputs.tf at PROJECT_ROOT/modules/terrahouse_aws
output "s3_website_endpoint" {
description = "website endpoint for the statically hosted website"
value = aws_s3_bucket_website_configuration
.website_configuration.website_endpoint # the entity from main.tf
}

# outputs.tf at PROJECT_ROOT
output "s3_website_endpoint" {
value = module.terrahouse_aws.website_endpoint # specify the output path.
}

3. Upload files using Terraform

Add the resources indexhtml & error_html which specify the attributes and path of the actual files. Make sure that the files are actually at the specified paths and the paths are correct.

resource "aws_s3_object" "index_html" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "index.html"
source = var.index_html_filepath
etag = filemd5("${path.root}/public/index.html")
}


resource "aws_s3_object" "error_html" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "error.html"
source = "${path.root}/public/error.html"
etag = filemd5("${path.root}/public/error.html")
}

4. Detect data change in files with Terraform

If you modify the code in files like index.html and error.html then try running terrafrom, you may notice that there is no changes to the infrastructure. So you may get a message like this:

This is because by default, terraform doesn’t run data check for change sets. It only compares the changes to the infrastructure. If you want to make sure terraform updates the infrastructures including files changes upon modifying the content of some of your files, you can inform terraform of this by using theetag attribute of aws_s3_bucket_object.

  • etag: Triggers updates when the value changes. See documentation as it requires strict formatting.
# main.tf

resource "aws_s3_object" "website_index" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "index.html"
source = "${path.root}/public/index.html"
+ etag = filemd5("${path.root}/public/index.html")
}

Then now run terraform apply and there will be changes.

5. Troubleshoot — Missing required argument

In order to use the module variables at root, we have to declare them in the module definition in main.tf at root.

module "terrahouse_aws" {
source = "./modules/terrahouse_aws"
user_uuid = var.user_uuid
bucket_name = var.bucket_name
+ index_html_filepath = var.index_html_filepath
+ error_html_filepath = var.error_html_filepath
}

Fixing Tags

Delete the latest tag

How to delete local and remote tags on Git

  • git tag -d <tag_name>: locally delete a tag
  • git push --delete origin <tag_name>: remotely delete tag

Fix previous tags (non-HEAD tags)

  • 1) checkout the commit that you want to re-tag.
  • 2) Grab the SHA from your Github commit history.
  • 3) Then run the following commands:
git checkout <SHA>
git tag M.M.P
git push --tags
git checkout main

Bash Command Cheat Sheet

# Download everything from your bucket to destination
aws s3 sync s3://YOUR_BUCKET_NAME .

# Empty bucket
aws s3 rm s3://YOUR_BUCKET_NAME --recursive

# Remove bucket
aws s3 rb s3://YOUR_BUCKET_NAME

Considerations when using Terraform to manage different types of resources

In this bootcamp, we are using Terraform for all three types of management:

  • Infrastructure (resources management)
  • Configurations
  • Files

Please note that Terraform is optimised and made for infrastructure management. Therefore, managing files (uploading and downloading) using terraform is not the best practice, all the more so in production environment although Terraform does offer the capabilities to manage other resources like configuration and files.

Resources

Terraform

Brilliant

--

--

Gwen Leigh

Cloud Engineer to be. Actively building my profile, network and experience in the cloud space. .