How to Create a simple static Amazon S3 website using Terraform
What is Terraform?
- HashiCorp Terraform is an infrastructure as code (IaC) tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share.
Please visit my previuos article on create a simple static website using amazon s3
Please visit my GitHub Repository for S3 articles on various topics being updated on constant basis.
Please visit my GitHub Repository for Terraform articles on various topics being updated on constant basis.
Let’s get started!
Objectives:
1. Sign in to AWS Management Console
2. Create the following organizational structure
3. Create files — index.html and error.html
4. Under s3_files
directory: Create 4 files - variables.tf
, terraform.tfvars
, main.tf
, outputs.tf
5. Initialize Terraform
6. To generate the action plans
7. Create all the resources declared in main.tf
configuration file
8. Validate all resources created
9. Test the S3 Static web site on the new web browser
Pre-requisites:
- AWS user account with admin access, not a root account.
- Cloud9 IDE with AWS CLI.
Resources Used:
Terraform documentation for AMI.
Tutorial: Configuring a static website on Amazon S3.
Steps for implementation to this project:
1. Sign in to AWS Management Console
- Make sure you’re in the N. Virginia (us-east-1) region
2. Let’s create the following organizational structure as shown below:
3. Create files — index.html and error.html
- Under s3_files directory, create a html folder, and then create error.html and index.html files in it.
- index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Creating a Static Website Using Amazon S3</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <style>
body {
padding-top: 5rem;
} .starter-template {
padding: 3rem 1.5rem;
text-align: center;
} .bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} @media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
</head><body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">My Static Website</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> <div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav> <main role="main" class="container"> <div class="starter-template">
<h1>Creating a Static Website Using Amazon S3</h1>
<p class="lead">Using Terraform, welcome to a simple static website, a cost-efficient website hosting for sites that consist of files like HTML, CSS, JavaScript, fonts, and images with a custom error page.
</p>
</div> <div class="starter-template alert alert-light" role="alert">
Navigation and search functions are intentionally not implemented.
</div> </main><!-- /.container --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
</script>
</body></html>
- error.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Creating a Static Website Using Amazon S3</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <style>
body {
padding-top: 5rem;
} .starter-template {
padding: 3rem 1.5rem;
text-align: center;
} .bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} @media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
} </style>
</head><body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">My Static Website</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> <div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav> <main role="main" class="container"> <div class="starter-template">
<h1>Custom Error Page</h1>
<p class="lead">Go to <a href="index.html">index.html page again</a>?</p>
</p>
</div> <div class="starter-template alert alert-light" role="alert">
Navigation and search functions are intentionally not implemented.
</div> </main><!-- /.container --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body></html>
4. Under s3_files
directory:
- Create 4 files —
variables.tf
,terraform.tfvars
,main.tf
,outputs.tf
- variables.tf — to declare all the global variables with a short description and a default value.
# required for AWS
variable "access_key" {
description = "Access key to AWS console"
}
variable "secret_key" {
description = "Secret key to AWS console"
}
variable "region" {
description = "Region of AWS VPC"
}
- 2. terraform.tfvars — Replace the values of access_key and secret_key by copying your AWS Access Key ID and Secret Access Key ID.
region = "us-east-1"
access_key = "<YOUR AWS CONSOLE ACCESS ID>"
secret_key = "<YOUR AWS CONSOLE SECRET KEY>"
- 3. main.tf — Creating a S3 bucket and its components
provider "aws" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}
##### Creating a Random String #####
resource "random_string" "random" {
length = 6
special = false
upper = false
} ##### Creating an S3 Bucket #####
resource "aws_s3_bucket" "bucket" {
bucket = "revbucket-${random_string.random.result}"
force_destroy = true
}resource "aws_s3_bucket_website_configuration" "blog" {
bucket = aws_s3_bucket.bucket.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}resource "aws_s3_bucket_public_access_block" "public_access_block" {
bucket = aws_s3_bucket.bucket.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}##### will upload all the files present under HTML folder to the S3 bucket #####
resource "aws_s3_object" "upload_object" {
for_each = fileset("html/", "*")
bucket = aws_s3_bucket.bucket.id
key = each.value
source = "html/${each.value}"
etag = filemd5("html/${each.value}")
content_type = "text/html"
}
- Apply Bucket Policy
- in S3, click the Permissions tab
- replace with your S3 bucket ARN
- Note: Ensure the trailing /* is present so the policy applies to all objects within the bucket.
{
"Version": "2012-10-17",
"Id": "Policy1234567890123",
"Statement": [
{
"Sid": "Stmt1234567890123",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::arn:aws:s3:::revbucket-npau9q/*"
}
]
}
- Click Save changes
- 4. outputs.tf — displays the output as website endpoint.
output "s3_bucket_id" {
value = aws_s3_bucket_website_configuration.blog.website_endpoint
}
5. Initialize Terraform
- terraform version
- terraform init will check for all the plugin dependencies and download them if required, this will be used for creating a deployment plan.
- Run
terraform init
6. To generate the action plans, run the below command:
- Run
terraform plan
7. Create all the resources declared in main.tf configuration file, run the below command:
- Run
terraform apply
- Wait for 4–5 minutes to create all the resources.
8. Validate all resources created
- s3 bucket
- index.html, error.html
9. Test the S3 Static web site on the new web browser
- Go to the properties tab of S3 bucket and scroll to the end of this page to find Static website hosting options.
- Copy the Bucket website endpoint and paste into the new tab of your web browser, with /index.html at the end.
- test error.html feature is working or not, replace index.html with rev.html.
- Now you should see the contents of error.html
Cleanup
- Run
terraform destroy
- Delete Cloud9 environment
What we have done so far
- Using Terraform, We created a static site using an AWS S3 bucket with the pre-created HTML files for your static web site.