# Building a Secure, Fast & Scalable Static Website on AWS - MindfulCloud

# Introduction

### The Problem It Solves

Anyone can host a static website on AWS, but that’s not enough in today's landscape. The real challenge is building a **secure, fast, and scalable** website that efficiently uses AWS resources.

* **Security Risks:** Hackers are everywhere, and a simple HTML file won’t stop them.
    
* **Performance Issues:** Users expect lightning-fast websites. Anything over a second and they bounce.
    
* **Cost Management:** Resources need to be allocated smartly to avoid unnecessary spending.
    

This blog walks you through building a **highly secure, performance-optimized** static website leveraging AWS services.

## How I Built It

The AWS services used:

* **AWS S3:** Foundation for static site storage.
    
* **CloudFront:** Distributes content worldwide for ultra-fast loading.
    
* **Certificate Manager:** Manages HTTPS encryption.
    
* **AWS WAF:** Protects against cyber threats like DDoS, XSS, and SQL Injection.
    
* **CloudWatch:** Monitors traffic, security, and performance with alerts.
    
* **AWS Route 53:** Manages the custom domain.
    

### This is the architecture for Hosting a Static Website

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741934848757/2969583a-46b5-430e-bcd3-d14dbf221c56.png align="center")

## Understanding the Architecture: The Complete Flow

1️⃣ **User Request (Entry Point)**

* A user visits **https://mindfulcloud.devsuraj.me**.
    
* The request is sent to **Amazon Route 53**, which maps the domain to CloudFront.
    

2️⃣ **Route 53 → CloudFront**

* Route 53 forwards the request to **Amazon CloudFront (CDN)**.
    
* CloudFront serves cached content to it’s edge locations near to the users for lower latency.
    

3️⃣ **Security Layer**

* **AWS WAF** protects against:
    
    * SQL Injection
        
    * Cross-site Scripting (XSS)
        
    * DDoS attacks
        
* **AWS ACM (AWS Certificate Manager)** enables **SSL/TLS encryption**.
    

4️⃣ **Fetching Content from S3**

* If CloudFront doesn’t have the content cached, it fetches it from **Amazon S3**.
    
* S3 acts as the **origin server** for static assets like HTML, CSS, JavaScript, and images.
    

5️⃣ **Monitoring & Logging**

* **AWS CloudWatch** tracks:
    
    * CloudFront request logs, cache hit ratio, and performance metrics.
        
    * S3 storage access patterns.
        
* Alerts notify about security threats or traffic spikes.
    

# Implementation

## Step 1: Setting Up an S3 Bucket for Static Website Hosting

1. Go to **AWS Console** **S3** service and **Create Bucket**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936179420/26c98294-5be0-40e6-a00b-17a1318a7e16.png align="center")
    
2. Enter a **unique bucket name** (e.g., [mindfulcloud.devsuraj.me](http://mindfulcloud.devsuraj.me)).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936242843/b601fcb5-87b9-47b4-b03b-3fb0e131fa24.png align="center")
    
3. Choose **public or private access** (public if hosting static content).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936256012/8fe9f031-300d-40ac-bad3-792614dd8dd8.png align="center")
    
4. Enable **static website hosting** under **Properties**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936336105/dbfb2316-af77-460a-8ad1-494357b9bc45.png align="center")
    
    **Scroll down below and enter the Index document and save it.**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936385873/3c0484e4-301a-41b2-ab2d-0de76b8fe891.png align="center")
    
5. Upload your static website files (HTML, CSS, JS).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936454088/96581c85-06a4-46ad-86ad-680ff196fee8.png align="center")
    

## Step 2: Configuring AWS ACM (SSL Certificate) for HTTPS

1. Go to **AWS Certificate Manager (ACM)** → **Request a Certificate**.
    
    You should create the certificate in the N.Verginia otherwise you’ll not be able to see it when you select the certificate in the cloudfront.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936507905/19de7840-f895-4a78-a5d5-12c236f5d88a.png align="center")
    
2. Choose **Public Certificate** → **Enter domain name** (e.g., [mindfulcloud.devsuraj.me](http://mindfulcloud.devsuraj.me)).
    
    In my case I have my root domain which `devsuraj.me` so I want subdomain to attach it and above I have mentioned.
    
3. Choose **DNS validation** (faster & recommended).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936582041/0da2c569-93a1-4b58-9a45-c182062ba4de.png align="center")
    
4. ACM provides **CNAME records**; add them to your **Namecheap DNS settings**.
    
    Copy the CNAME name and CNAME value.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936692597/44ae53ce-e35b-419b-9b6c-3f358e64e166.png align="center")
    
    **Add it to the DNS service provide you have in my case I have Namecheap:**
    
    1. After login to you namecheap to **domain list and click on manage and go to the advanced DNS.**
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936855801/da52e500-2fdd-489d-8436-251d9ba35198.png align="center")
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936932660/167695bc-5ee3-439e-beb5-5cac5824a937.png align="center")
        
    2. Now create new record
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741936988454/bad3a968-4ef7-45ba-804c-df0894df790c.png align="center")
        
    3. Enter the CNAME and The Value
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937059909/bde2292c-bff5-497d-94f5-c83776ef660a.png align="center")
        
5. Now you’re done with ACM, wait for validation (may take a few minutes to hours).
    

## Step 3: Setting Up a Route 53 Hosted Zone

1. Go to **AWS Route 53** → **Create Hosted Zone**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937278726/1d5f3848-1535-462d-b7af-6bc4324ee223.png align="center")
    
2. Enter your subdomain (e.g., [mindfulcloud.devsuraj.me](http://mindfulcloud.devsuraj.me)).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937316935/9c49f832-2900-448d-bb07-0b54122cc50d.png align="center")
    
3. Copy the provided **NS (Name Server) records** and update them in **Namecheap’s DNS settings**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937364181/f080c810-24bd-4c61-8a6b-64af039e2e78.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937411428/3d461340-949d-4f9d-87bd-06b810537e9b.png align="center")
    
4. Create an **A record** (alias) pointing to **CloudFront Distribution**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937481808/12063eed-8512-4c9e-a3da-d31119e9e58c.png align="center")
    

## Step 4: Setting Up CloudFront for CDN & Caching

1. Go to **AWS CloudFront** → **Create Distribution**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937620661/752f1322-52e6-4f3e-a303-d0418b57b5d1.png align="center")
    
2. Set **Origin Domain** as your S3 bucket.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937675982/8cb2b5fd-978d-49b8-b517-571343f8da8a.png align="center")
    
3. Enable **HTTPS** using your ACM certificate.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937719854/634b15b3-7601-47c5-a0fa-6c8b79f93978.png align="center")
    
    **Select you ACM certificate:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741938040610/2a2272de-dbcd-479b-a822-c9e363d9855b.png align="center")
    
4. Configure **default root object** (index.html).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741937830674/8f3b498f-e483-4ab5-8294-5f8e75701377.png align="center")
    
5. Deploy the distribution and note the **CloudFront URL**.
    
6. After creating the distribution it you’ll give you the bucket policy to you just copy that and paste it in the bucket you created:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939790925/b5326d2b-a8d7-4ad9-b594-4f5292812bfb.png align="center")
    

## **Step 5: Connecting Namecheap Domain to AWS**

#### **1️⃣ Go to Namecheap DNS Settings**

* Log in to **Namecheap** → **Domain List** → **Manage** your domain → **Advanced DNS**.
    

#### **2️⃣ Verify NS Records are correct( as we did this in step 3)**

* Ensure **Nameservers** are set to **Custom DNS** with Route 53 NS records.
    

#### **3️⃣ Save & Wait for Propagation**

* Click **Save Changes** → Wait **a few minutes to 24 hours**.
    
* Open [`https://yourdomain.com`](https://mindfulcloud.devsuraj.me) in a browser to confirm it works.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741934637323/c090c826-03be-457a-9f71-e0d40b2ba74c.png align="center")

## Step 6: Enhancing Security with AWS WAF

1. Go to **AWS WAF** → **Create WebACL**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741938495635/3272157f-05b8-47eb-b042-cb3cfcc11be9.png align="center")
    
2. Attach it to **CloudFront Distribution**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741938621461/470152fc-19ac-4371-a586-c38b1f331875.png align="center")
    
3. Add security rules:
    
    * **Block common threats** (DDoS, SQL Injection, XSS attacks).
        
    * **Rate limiting** for excessive requests.
        
    * **Geo-restriction** to block traffic from unwanted locations.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741938708441/68e33ba9-c921-45eb-9b21-ecdffefaec7d.png align="center")
    
4. Enable **AWS WAF logging** to monitor security threats.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741938751012/ac9b3e8e-a90b-4e98-9aaa-6ee7513e790a.png align="center")
    

## Step 7: Enabling CloudWatch Monitoring & Logging

1. **Enable CloudFront Logging**:
    
    * Go to **CloudFront** → **Enable Standard Logging**.
        
    * Choose an **S3 bucket** to store logs.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939080782/1676e8f4-5f32-4192-9f77-3ef76aeacaec.png align="center")
    
2. **Create CloudWatch Dashboards**:
    
    * Monitor **requests, latency, cache hit ratio**.
        
    * Set up **CloudWatch alarms** for security events.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939126900/0f60cb5f-56ee-49ac-9ce8-42fcad14767b.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939166984/efa1da91-d747-4af2-a9bb-bd888926ae61.png align="center")
    
3. **Set Up Alerts**:
    
    * Use **AWS SNS (Simple Notification Service)** to receive alerts via email/SMS.
        
    * Example: Alert if **CloudFront request count exceeds a threshold**.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939196683/643c1916-5063-418b-9990-eb3761999501.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939225941/7f112d6e-e9bc-4bfe-ab88-206268bc90fb.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939245897/0c15274a-ad3b-4827-bfd4-2b20dbf754e2.png align="center")
    
    **Select The SNS topic or create one:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939277290/73c9ca7e-f59c-438e-adc4-90d9316c0572.png align="center")
    
4. And just complete the step 3 and step 4 in creating the alarm and you’re good go.
    

## Step 8: Implementing Reliability & Disaster Recovery

1. **Enable S3 Versioning**:
    
    * Go to **S3** → **Properties** → **Enable Versioning**.
        
    * This helps rollback in case of accidental file deletion.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939409370/487fa00a-b0a4-4805-8740-5496212985fb.png align="center")
    
2. **Enable Cross-Region Replication**:
    
    * Go to **S3** → **Replication Rules** → **Set up a backup region**.
        
    * Choose a different AWS region for redundancy.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939858163/7583db07-78b4-430b-a8c9-63abfdf88141.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741939832570/14ef29f7-bbb5-4f2f-8b2e-210b2defa017.png align="center")
    

## **Send the requests to your website to check the performance, WAF security and other metrics.**

```bash
#!/bin/bash

URL="your website url"
REQUESTS='' # include the number of requrests you want to send  

echo "Starting load test on $URL with $REQUESTS requests..."

for ((i=1; i<=REQUESTS; i++))
do
  curl -s -o /dev/null -w "Request $i: HTTP %{http_code}\n" $URL &
done

echo "Load test initiated!"
```

### **How to Run**

1. Save this script as `simple_load_`[`test.sh`](http://test.sh).
    
2. Give it execution permission:
    

```bash
chmod +x simple_load_test.sh
```

3. Run it:
    

```bash
./simple_load_test.sh
```

## The end!!!

### Thanks for the reading guys, see you in the next one…
