Skip to main content

Building a Static Website on AWS with Terraform


The Journey to a Fully Automated Website Deployment

A few weeks ago, I found myself needing to deploy a simple static website. Manually setting up an S3 bucket, configuring permissions, and linking it to a CloudFront distribution seemed like a tedious process. As someone who loves automation, I decided to leverage Terraform to simplify the entire process.

Why Terraform?

Infrastructure as Code (IaC) is a game-changer. With Terraform, I could:  Avoid manual setup errors  Easily reproduce and  Automate security best practices

Instead of clicking through AWS settings, I wrote a few Terraform scripts and deployed everything in minutes. Let me walk you through how I did it!




 Architecture Overview




The architecture consists of three main components:

User: The end user accesses the website via a CloudFront URL. 

CloudFront Distribution: Acts as a content delivery network (CDN) to distribute content efficiently, reduce latency, and enhance security. It fetches content from the S3 bucket. 

S3 Bucket: Stores static website files securely. Direct access is restricted, and only CloudFront can retrieve content from it. Stores static website files securely. Direct access is restricted, and only CloudFront can retrieve content from it.



Step 1: Hosting on S3

To serve my static website, I needed an S3 bucket. However, I didn't want it to be public since AWS strongly discourages public S3 access. The plan? Make it private and use CloudFront as a secure gateway.

With Terraform, I quickly set up the bucket:

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-cloudfront-secure-bucket"
}

I also uploaded my website files (index.html, index.css, and logo.png) automatically with Terraform. No need to manually drag and drop!


Step 2: Ensuring Security

Now, here's the tricky part: AWS, by default, blocks public access to S3. To prevent unauthorized access, I applied a policy restricting direct access but allowing CloudFront to fetch content:

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.my_bucket.id
  policy = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontAccess",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-cloudfront-secure-bucket/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "${aws_cloudfront_distribution.my_distribution.arn}"
                }
            }
        }
    ]
}
POLICY
}

This means my S3 files remain invisible to the public but are accessible through CloudFront. 



Step 3: Configuring Origin Access Control (OAC) for CloudFront

To enhance security, I configured Origin Access Control (OAC), which ensures that only CloudFront can retrieve objects from my private S3 bucket. This prevents direct access to files and enforces controlled access.

resource "aws_cloudfront_origin_access_control" "oac" {
  name                              = "MyOAC"
  description                       = "OAC for CloudFront to access S3"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

By implementing OAC, CloudFront authenticates requests to S3 and prevents users from bypassing the CDN, ensuring better security and performance.



Step 4: Speeding Things Up with CloudFront

CloudFront is AWS’s CDN (Content Delivery Network). By using it, my website loads faster, and I get better security. Plus, I avoid exposing my S3 bucket directly to users.

Configuring CloudFront with Terraform was surprisingly easy:

resource "aws_cloudfront_distribution" "my_distribution" {
  origin {
    domain_name              = aws_s3_bucket.my_bucket.bucket_regional_domain_name
    origin_id                = "S3Origin"
    origin_access_control_id = aws_cloudfront_origin_access_control.oac.id
  }

  enabled             = true
  default_root_object = "index.html"
}

Now, whenever users visit my CloudFront URL, they see my website—without knowing that the files are stored privately in S3.


The Moment of Truth


Deploying the Website

With a simple terraform apply, everything was created in AWS within minutes. No manual clicks. No forgotten settings. Just pure, automated infrastructure deployment.

I ran:

terraform apply

At the end of the process,you will have a message (The output below is an example)

Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

Outputs:

bucket_name = "my-cloudfront-secure-bucket"

cloudfront_url = "d2rcd4t32u4otq.cloudfront.net"


And there it was—my very own CloudFront URL, hosting my static website with speed and security. 

🔗 Example URL (not real, it is based on the example) : d2rcd4t32u4otq.cloudfront.net/index.html





Conclusion

You can find the full Terraform configuration and setup details in the GitHub repository: terraform-infra Static Website

Terraform turned what could have been a frustrating manual deployment into an easy, repeatable process. Now, if I need to tweak my website or migrate to a new region, I just update my code and redeploy.

If you're looking for a secure, scalable, and automated way to host your static websites, Terraform is the way to go! 


Comments

Popular posts from this blog

FastAPI Instrumentalisation with prometheus and grafana Part1 [Counter]

welcome to this hands-on lab on API instrumentation using Prometheus and FastAPI! In the world of modern software development, real-time API monitoring is essential for understanding usage patterns, debugging issues, and ensuring optimal performance. In this lab, we’ll demonstrate how to enhance a FastAPI-based application with Prometheus metrics to monitor its behavior effectively. We’ve already set up the lab environment for you, complete with Grafana, Prometheus, and a PostgreSQL database. While FastAPI’s integration with databases is outside the scope of this lab, our focus will be entirely on instrumentation and monitoring. For those interested in exploring the database integration or testing , you can review the code in our repository: FastAPI Monitoring Repository . What You’ll Learn In this lab, we’ll walk you through: Setting up Prometheus metrics in a FastAPI application. Instrumenting API endpoints to track: Number of requests HTTP methods Request paths Using Grafana to vi...

Join Ubuntu 20.04 to Active Directory with SSSD and SSH Access

Join Ubuntu 20.04 to Active Directory with SSSD and SSH Access  Overview This guide walks you through joining an Ubuntu 20.04 machine to an Active Directory domain using SSSD, configuring PAM for AD user logins over SSH, and enabling automatic creation of home directories upon first login. We’ll also cover troubleshooting steps and verification commands. Environment Used Component Value Ubuntu Client       ubuntu-client.bazboutey.local Active Directory FQDN   bazboutey.local Realm (Kerberos)   BAZBOUTEY.LOCAL AD Admin Account   Administrator Step 1: Prerequisites and Package Installation 1.1 Update system and install required packages bash sudo apt update sudo apt install realmd sssd libnss-sss libpam-sss adcli \ samba-common-bin oddjob oddjob-mkhomedir packagekit \ libpam-modules openssh-server Step 2: Test DNS and Kerberos Configuration Ensure that the client can resolve the AD domain and discover services. 2.1 Test domain name resol...

Observability with grafana and prometheus (SSO configutation with active directory)

How to Set Up Grafana Single Sign-On (SSO) with Active Directory (AD) Grafana is a powerful tool for monitoring and visualizing data. Integrating it with Active Directory (AD) for Single Sign-On (SSO) can streamline access and enhance security. This tutorial will guide you through the process of configuring Grafana with AD for SSO. Prerequisites Active Directory Domain : Ensure you have an AD domain set up. Domain: bazboutey.local AD Server IP: 192.168.170.212 Users: grafana (for binding AD) user1 (to demonstrate SSO) we will end up with a pattern like this below Grafana Installed : Install Grafana on your server. Grafana Server IP: 192.168.179.185 Administrator Privileges : Access to modify AD settings and Grafana configurations. Step 1: Configure AD for LDAP Integration Create a Service Account in AD: Open Active Directory Users and Computers. Create a user (e.g., grafana ). Assign this user a strong password (e.g., Grafana 123$ ) and ensure it doesn’t expire. Gather Required AD D...