How to Create a simple static Amazon S3 website using Terraform
Tags: s3, terraform
Published: 2023-09-19 00:23:45

# 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](https://dev.to/aws-builders/how-to-create-a-simple-static-website-using-amazon-s3-e0b)**

Please visit my **[GitHub Repository for S3 articles](https://github.com/awsmine/S3_projects)** on various topics being updated on constant basis.

Please visit my **[GitHub Repository for Terraform articles](https://github.com/awsmine/Terraform_projects)** 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](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami).***

***[Tutorial: Configuring a static website on Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html).***

# 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:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbxmubkoxsj3oinimbdq.png)



## 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`***



- 1. 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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/job28atgstczg72ga01r.png)


- 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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23z55jveygwda1ybees6.png)



- 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`***


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd6bh6lq4266arli632b.png)



## 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.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4u8ka7sx5o3vsrk7duct.png)




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kpv6u4ty565hhpy34m9p.png)


## 8. Validate all resources created
 - s3 bucket

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8btrmnng1axw073l6emg.png)

- index.html, error.html


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkqrxfay5hqdqsoacdpa.png)




## 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.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abtyze3ines231ijdzis.png)




- test error.html feature is working or not, replace index.html with rev.html. 
- Now you should see the contents of error.html


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq17vcjl1k6rcz63qf3l.png)



# Cleanup

- Run ***`terraform destroy`***

- Delete Cloud9 environment

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/39b5pruxeei9eckltk90.png)


# 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.