S3 Bucket as Static Website using Terraform

Raghav D
7 min readMay 19, 2021

S3 bucket is the object level storage solution by AWS services, We can store any kind of data, we can upload maximum 5TB data as a single file.

Configure S3 bucket as static website with the below steps:

Step1: Create a bucket

Step2: Enable static website hosting

Step3: Make bucket contents as public, attach the policy

Step4: configure index.html, error.html documents
index.html

<body style="background-color:#FAEBD7"></body><body><h1>S3 bucket as static website using terraform deployments</h1><h2>Raghav Dandothkar</h2><h3> Visit <a href="https://raghavendar-d.medium.com/" target="_blank" rel="noopener noreferrer">https://raghavendar-d.medium.com </a>for all my articles on AWS</h3><h4>s3 bucket as static website</h4><img src="image.jpg" ></br><a href = "mailto: raghavendrads22@gmail.com">raghavendrads22@gmail.com</a></body>

error.html

<body style="background-color:#FAEBD7"></body><body><h1>Due to haeavy traffic on site, we are unable to process your request, so kindly reach us again ...!!!</h1><img src="error.jpeg" ></br></body>

Step5: Test your website endpoint

Below will be the policy.json file

{“Version”: “2012–10–17”,“Statement”: [{“Sid”: “PublicReadGetObject”,“Effect”: “Allow”,“Principal”: “*”,“Action”: [“s3:GetObject”],“Resource”: [“arn:aws:s3:::raghav.terraform-tutorials.com/*”]}]}

We will implement above steps using Terraform
Crete a bucket and attach the policy, enable the static website in main.tf file
###start of main.tf file ####

resource “aws_s3_bucket” “mywebsite” {bucket = “raghav.terraform-tutorials.com”acl = “public-read”policy = file(“policy.json”)website {index_document = “index.html”error_document = “error.html”}tags = {Name = “My website Bucket”Environment = “Terraform”}}2. Copy the index.html and error.html files in the bucketresource “aws_s3_bucket_object” “index” {bucket = aws_s3_bucket.mywebsite.idacl = “public-read” # or can be “public-read”key = “index.html”source = “./index.html”etag = filemd5(“./index.html”)content_type = “text/html”}resource “aws_s3_bucket_object” “error” {bucket = aws_s3_bucket.mywebsite.idacl = “public-read” # or can be “public-read”key = “error.html”source = “./error.html”etag = filemd5(“./error.html”)content_type = “text/html”}resource “aws_s3_bucket_object” “image” {bucket = aws_s3_bucket.mywebsite.idacl = “public-read” # or can be “public-read”key = “image.jpg”source = “./image.jpg”etag = filemd5(“./image.jpg”)}resource “aws_s3_bucket_object” “error_image” {bucket = aws_s3_bucket.mywebsite.idacl = “public-read” # or can be “public-read”key = “error.jpeg”source = “./error.jpeg”etag = filemd5(“./error.jpeg”)}
####EOF main.tf####

variable.tf file

variable “stage” {}variable “project_name” {}variable “region” {}

provider.tf file

provider “aws” {profile = “<profile name>”}

###EOF ####

output.tf which gives bucket domain name as output 
output “bucket_domain_name” {
value = aws_s3_bucket.mywebsite.website_endpoint} ####EOF###

Now we have our terraform code, index.html, error.html, images. Now we will deploy our terraform codes, execute the below code

terraform init

terraform plan
output of terraform plan:


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:# aws_s3_bucket.mywebsite will be created
+ resource “aws_s3_bucket” “mywebsite” {
+ acceleration_status = (known after apply)
+ acl = “public-read”
+ arn = (known after apply)
+ bucket = “raghav.terraform-tutorials.com”
+ bucket_domain_name = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ policy = jsonencode(
{
+ Statement = [
+ {
+ Action = [
+ “s3:GetObject”,
]
+ Effect = “Allow”
+ Principal = “*”
+ Resource = [
+ “arn:aws:s3:::raghav.terraform-tutorials.com/*”,
]
+ Sid = “PublicReadGetObject”
},
]
+ Version = “2012–10–17”
}
)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = {
+ “Environment” = “Terraform”
+ “Name” = “My website Bucket”
}
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
+ versioning {
+ enabled = (known after apply)
+ mfa_delete = (known after apply)
}
+ website {
+ error_document = “error.html”
+ index_document = “index.html”
}
}
# aws_s3_bucket_object.error will be created
+ resource “aws_s3_bucket_object” “error” {
+ acl = “public-read”
+ bucket = (known after apply)
+ content_type = “text/html”
+ etag = “1133662cd575094e6a2d27721b83b358”
+ force_destroy = false
+ id = (known after apply)
+ key = “error.html”
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = “./error.html”
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.error_image will be created
+ resource “aws_s3_bucket_object” “error_image” {
+ acl = “public-read”
+ bucket = (known after apply)
+ content_type = (known after apply)
+ etag = “4d6cea82c2010a3fb06fc640c4ca7023”
+ force_destroy = false
+ id = (known after apply)
+ key = “error.jpeg”
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = “./error.jpeg”
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.image will be created
+ resource “aws_s3_bucket_object” “image” {
+ acl = “public-read”
+ bucket = (known after apply)
+ content_type = (known after apply)
+ etag = “c91962a18ed49f897e70d36a6db99828”
+ force_destroy = false
+ id = (known after apply)
+ key = “image.jpg”
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = “./image.jpg”
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.index will be created
+ resource “aws_s3_bucket_object” “index” {
+ acl = “public-read”
+ bucket = (known after apply)
+ content_type = “text/html”
+ etag = “f885f6429210e93f4180e9b8720896a8”
+ force_destroy = false
+ id = (known after apply)
+ key = “index.html”
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = “./index.html”
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
Plan: 5 to add, 0 to change, 0 to destroy.

plan looks good

lets apply the changes, so we will execute the terraform apply command

terraform apply
var.project_name
Enter a value: raghav-terraform
var.region
Enter a value: us-east-1
var.stage
Enter a value: terraform
provider.aws.region
The region where AWS operations will take place. Examples
are us-east-1, us-west-2, etc.
Enter a value: us-east-1aws_s3_bucket.mywebsite: Refreshing state... [id=raghav.terraform-tutorials.com]
aws_s3_bucket_object.error: Refreshing state... [id=error.html]
aws_s3_bucket_object.image: Refreshing state... [id=image.jpg]
aws_s3_bucket_object.error_image: Refreshing state... [id=error.jpeg]
aws_s3_bucket_object.index: Refreshing state... [id=index.html]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:# aws_s3_bucket.mywebsite will be created
+ resource "aws_s3_bucket" "mywebsite" {
+ acceleration_status = (known after apply)
+ acl = "public-read"
+ arn = (known after apply)
+ bucket = "raghav.terraform-tutorials.com"
+ bucket_domain_name = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ policy = jsonencode(
{
+ Statement = [
+ {
+ Action = [
+ "s3:GetObject",
]
+ Effect = "Allow"
+ Principal = "*"
+ Resource = [
+ "arn:aws:s3:::raghav.terraform-tutorials.com/*",
]
+ Sid = "PublicReadGetObject"
},
]
+ Version = "2012-10-17"
}
)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags = {
+ "Environment" = "Terraform"
+ "Name" = "My website Bucket"
}
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
+ versioning {
+ enabled = (known after apply)
+ mfa_delete = (known after apply)
}
+ website {
+ error_document = "error.html"
+ index_document = "index.html"
}
}
# aws_s3_bucket_object.error will be created
+ resource "aws_s3_bucket_object" "error" {
+ acl = "public-read"
+ bucket = (known after apply)
+ content_type = "text/html"
+ etag = "1133662cd575094e6a2d27721b83b358"
+ force_destroy = false
+ id = (known after apply)
+ key = "error.html"
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = "./error.html"
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.error_image will be created
+ resource "aws_s3_bucket_object" "error_image" {
+ acl = "public-read"
+ bucket = (known after apply)
+ content_type = (known after apply)
+ etag = "4d6cea82c2010a3fb06fc640c4ca7023"
+ force_destroy = false
+ id = (known after apply)
+ key = "error.jpeg"
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = "./error.jpeg"
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.image will be created
+ resource "aws_s3_bucket_object" "image" {
+ acl = "public-read"
+ bucket = (known after apply)
+ content_type = (known after apply)
+ etag = "c91962a18ed49f897e70d36a6db99828"
+ force_destroy = false
+ id = (known after apply)
+ key = "image.jpg"
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = "./image.jpg"
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
# aws_s3_bucket_object.index will be created
+ resource "aws_s3_bucket_object" "index" {
+ acl = "public-read"
+ bucket = (known after apply)
+ content_type = "text/html"
+ etag = "f885f6429210e93f4180e9b8720896a8"
+ force_destroy = false
+ id = (known after apply)
+ key = "index.html"
+ kms_key_id = (known after apply)
+ server_side_encryption = (known after apply)
+ source = "./index.html"
+ storage_class = (known after apply)
+ version_id = (known after apply)
}
Plan: 5 to add, 0 to change, 0 to destroy.Changes to Outputs:
~ bucket_domain_name = "raghav.terraform-tutorials.com.s3-website-us-east-1.amazonaws.com" -> (known after apply)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yesaws_s3_bucket.mywebsite: Creating...
aws_s3_bucket.mywebsite: Still creating... [10s elapsed]
aws_s3_bucket.mywebsite: Still creating... [20s elapsed]
aws_s3_bucket.mywebsite: Creation complete after 26s [id=raghav.terraform-tutorials.com]
aws_s3_bucket_object.error_image: Creating...
aws_s3_bucket_object.image: Creating...
aws_s3_bucket_object.index: Creating...
aws_s3_bucket_object.error: Creating...
aws_s3_bucket_object.error_image: Creation complete after 4s [id=error.jpeg]
aws_s3_bucket_object.index: Creation complete after 4s [id=index.html]
aws_s3_bucket_object.error: Creation complete after 4s [id=error.html]
aws_s3_bucket_object.image: Creation complete after 5s [id=image.jpg]
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.Outputs:bucket_domain_name = "raghav.terraform-tutorials.com.s3-website-us-east-1.amazonaws.com"
terraform apply command
s3 bucket hosting as static website

We have hosted our static website on AWS S3 bucket

References:

  1. https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html
  2. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket

--

--