AWS with Terraform (Day 14)

Hosting a Static Website on AWS S3 + CloudFront + Rout53 Using Terraform


Today in my “30 Days of AWS & Terraform” learning journey, I explored how to host a production-grade static website using AWS S3 and CloudFront, with the entire setup automated via Terraform. This combination provides high availability, global content delivery, strong security, and low cost — all while remaining fully repeatable through Infrastructure-as-Code.


Why CloudFront with S3?

A static site hosted directly on S3 works, but it isn’t ideal for real users worldwide. Problems include:

  • High latency for users far from the S3 region

  • Increased cost due to regional data transfer

  • Security risks when buckets are made public

CloudFront solves these by caching content in global edge locations, reducing load time and ensuring users never directly access the S3 bucket. Instead, CloudFront communicates with S3 using Origin Access Control (OAC), keeping the bucket private and secure.


High-Level Architecture

ComponentPurpose
S3 Bucket (private)        Stores static web files (HTML, CSS, JS, images)
CloudFront Distribution        Serves and caches content globally
Origin Access Control        Allows only CloudFront to pull from S3
Bucket Policy        Restricts access to CloudFront ARN
(Optional) ACM + Route 53           Custom domain + HTTPS

Terraform Resources Used

The key Terraform components for this setup:

  • aws_s3_bucket

  • aws_s3_bucket_public_access_block

  • aws_cloudfront_origin_access_control

  • aws_cloudfront_distribution

  • aws_s3_bucket_policy

  • aws_s3_bucket_object (for uploading files)

Useful Terraform functions & patterns:

fileset(path.module, "www/**") filemd5() for_each lookup() jsonencode()

These enable automated file uploads, intelligent cache busting, and clean policy handling.


Common Gotchas & Tips

Use Origin Access Control, not deprecated OAI
Ensure bucket policy uses correct object ARN (/*)
Don’t mix bucket-level and object-level permissions
CloudFront creation/update takes time — be patient
Use invalidation only for urgent refreshes


Production-Ready Checklist

FeatureStatus
Custom domain via Route 53    Recommended
SSL via AWS Certificate Manager (us-east-1)        Required for HTTPS
CI/CD integration    Upload site + apply Terraform
Security headers / Error pages    Best practice
Remote backend for Terraform state    Strongly recommended

Key Takeaway

Always keep your S3 bucket private. Serve content only through CloudFront for maximum security, speed, and cost efficiency.

Terraform makes static site hosting predictable, version-controlled, and reusable. With modular structure, replicating environments like dev / stage / prod becomes effortless.


Final Thoughts

This exercise strengthened my understanding of real-world DevOps practices: security, scalability, automation, and global performance optimization. Starting from a basic bucket and distribution helped build up step-by-step confidence before integrating Route 53 and ACM.

If you’re deploying static sites — portfolio, documentation, landing pages, or dashboards — this architecture is powerful and production-ready.


Diagram




Here is my repo link: https://github.com/Mo-Adnan-Mo-Ayyub/Aws-with-Terraform

Here is today's session link:



Comments

Popular posts from this blog

AWS with Terraform (Day 01)

AWS with Terraform (Day 02)

AWS with Terraform (Day 06)