S3 Bucket as Static Website using Terraform

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:
+ createTerraform 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-terraformvar.region
Enter a value: us-east-1var.stage
Enter a value: terraformprovider.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:
+ createTerraform 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"


We have hosted our static website on AWS S3 bucket
References: