Terraform Tutorial — Project 1: S3 Static Website

1 minute read

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.


← Practice Projects Hub Project 2: EC2 Web Server →