Hosting a Static Website on AWS S3 Using Terraform
What is AWS S3?
Amazon Simple Storage Service (S3) is a highly scalable, durable, and secure object storage
service offered by AWS. It allows you to store and retrieve any amount of data at any time,
from anywhere on the web.
Key Features:
• Object storage for any type of file (HTML, images, videos, backups, etc.)
• 99.999999999% (11 9’s) durability
• Static website hosting support
• Lifecycle policies for automatic data management
• Access control using IAM policies, bucket policies, and ACLs
Static Website Hosting with S3:
You can configure an S3 bucket to act as a web server, serving static content such as HTML,
CSS, JS files. It supports:
• Index and error document configuration
• Public read access through bucket policy
• Integration with CloudFront for CDN and HTTP
Prerequisites
• AWS CLI configured (aws configure)
• IAM user with S3 full access
• Terraform installed
• [Link] and [Link] files present in your working directory
[Link]
<html xmlns="[Link] >
<head>
<title>My Website Home Page</title>
</head>
<body>
<h1>Welcome to my website</h1>
<p>Now hosted on Amazon S3!</p>
</body>
</html>
[Link]
<!-- [Link] -->
<!DOCTYPE html>
<html>
<head><title>Error</title></head>
<body><h1>Oops! Something went wrong.</h1></body>
</html>
Create file
[Link]
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "static_site" {
bucket = "my-static-site-bucket-priyanka1" # Must be globally unique
website {
index_document = "[Link]"
error_document = "[Link]"
}
tags = {
Name = "StaticSite"
}
}
# Disable block public access (to allow public read via policy)
resource "aws_s3_bucket_public_access_block" "public_access" {
bucket = aws_s3_bucket.static_site.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
# Set ownership controls
resource "aws_s3_bucket_ownership_controls" "ownership" {
bucket = aws_s3_bucket.static_site.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
# Add a public read policy for all objects
resource "aws_s3_bucket_policy" "policy" {
depends_on = [aws_s3_bucket_public_access_block.public_access]
bucket = aws_s3_bucket.static_site.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Sid = "PublicReadGetObject",
Effect = "Allow",
Principal = "*",
Action = "s3:GetObject",
Resource = "${aws_s3_bucket.static_site.arn}/*"
}
]
})
}
# Upload [Link]
resource "aws_s3_object" "index" {
bucket = aws_s3_bucket.static_site.id
key = "[Link]"
source = "[Link]"
content_type = "text/html"
}
# Upload [Link]
resource "aws_s3_object" "error" {
bucket = aws_s3_bucket.static_site.id
key = "[Link]"
source = "[Link]"
content_type = "text/html"
}
# Output website URL
output "website_url" {
value = aws_s3_bucket.static_site.website_endpoint
}
Breakdown :
1. AWS Provider Configuration
provider "aws" {
region = "us-east-1"
This tells Terraform to use the AWS provider and to deploy resources in the us-east-1 (N.
Virginia) region.
2. Create the S3 Bucket
resource "aws_s3_bucket" "static_site" {
bucket = "my-static-site-bucket-priyanka1"
• Creates a globally unique S3 bucket named my-static-site-bucket-priyanka1.
website {
index_document = "[Link]"
error_document = "[Link]"
• Enables static website hosting.
• Configures the landing page ([Link]) and a custom error page ([Link]).
tags = {
Name = "StaticSite"
• Adds a tag to identify the resource.
3. Allow Public Access
resource "aws_s3_bucket_public_access_block" "public_access" {
This resource disables the "Block Public Access" settings so that public policies and ACLs
can be used:
• false for all flags to allow public access.
4. Set Bucket Ownership
resource "aws_s3_bucket_ownership_controls" "ownership" {
...
This sets the object ownership to "BucketOwnerPreferred", allowing the bucket owner full
control over objects.
5. Public Read Bucket Policy
resource "aws_s3_bucket_policy" "policy" {
...
Defines a bucket policy that:
• Allows everyone (Principal = "*") to read objects (s3:GetObject) inside the bucket.
• Depends on the public_access_block being set to allow public policies.
6. Upload [Link] and [Link]
resource "aws_s3_object" "index" {
resource "aws_s3_object" "error" {
}
Uploads:
• [Link] and [Link] from your local machine into the S3 bucket.
• Sets content_type = "text/html" so they’re treated as web pages.
7. Output Website URL
output "website_url" {
value = aws_s3_bucket.static_site.website_endpoint
This prints the public S3 website URL after Terraform finishes applying.
Step-by-Step Terraform Commands
1. Initialize Terraform
terraform init
• Purpose: Downloads the AWS provider and prepares the backend.
• Output: You'll see a success message like "Terraform has been successfully
initialized!"
2. Review the Execution Plan
terraform plan
• Purpose: Shows you what Terraform will do without making changes.
• Output: Lists all the resources that will be created (e.g., aws_s3_bucket,
aws_s3_object, etc.).
3. Apply the Plan
terraform apply
•
• Purpose: Actually creates the resources on AWS.
• Prompt: You’ll be asked to confirm with yes.
• Output: On success, you'll see the website_url printed at the end.
Sample Output at the End
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
website_url = "[Link]
You can now open that URL in your browser to view your static website!
Check Bucket is created
Important Notes:
• Make sure [Link] and [Link] exist in your working directory.
• Your IAM user (user1) must have permissions to:
o Create S3 buckets
o Put bucket policies
o Upload objects
o Disable public access block settings