Terraform Tutorial — Project 1: S3 Static Website
Create an S3 bucket configured for static website hosting with a bucket policy that allows public read access.
What You’ll Build
- S3 bucket with website hosting enabled
- Bucket policy for public read access
- Output the website URL
Project Structure
project-1-s3-website/
├── main.tf
├── variables.tf
├── outputs.tf
└── index.html
variables.tf
variable "bucket_name" {
type = string
description = "Name of the S3 bucket (must be globally unique)"
}
variable "region" {
type = string
default = "us-east-1"
}
main.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.region
}
resource "aws_s3_bucket" "website" {
bucket = var.bucket_name
tags = {
Purpose = "static-website"
}
}
resource "aws_s3_bucket_website_configuration" "website" {
bucket = aws_s3_bucket.website.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
resource "aws_s3_bucket_public_access_block" "website" {
bucket = aws_s3_bucket.website.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_policy" "website" {
bucket = aws_s3_bucket.website.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.website.arn}/*"
}
]
})
depends_on = [aws_s3_bucket_public_access_block.website]
}
resource "aws_s3_object" "index" {
bucket = aws_s3_bucket.website.id
key = "index.html"
source = "index.html"
content_type = "text/html"
}
outputs.tf
output "website_url" {
value = aws_s3_bucket_website_configuration.website.website_endpoint
description = "URL of the static website"
}
output "bucket_arn" {
value = aws_s3_bucket.website.arn
}
Deploy
$ terraform init
$ terraform plan -var="bucket_name=my-unique-website-bucket-12345"
$ terraform apply -var="bucket_name=my-unique-website-bucket-12345"
# Visit the website
$ open $(terraform output -raw website_url)
# Clean up
$ terraform destroy -var="bucket_name=my-unique-website-bucket-12345"
What’s Next?
Build something more complex — an EC2 web server.