DEV Community

PRASANTH M
PRASANTH M

Posted on

CLOUD WORKSHOP DAY 1 SESSION 1

I Built and Deployed My First Portfolio on AWS S3 + CloudFront — And Broke It Along the Way

As an M.Sc Artificial Intelligence and Machine Learning student, I've been trying to move away from just writing code by following tutorials and actually understand how things work by building and deploying projects.

One of the things I wanted to build was a simple personal portfolio.

It sounded easy:

Build a portfolio → upload it to AWS → get a public URL.

It wasn't quite that simple.

I ran into permissions issues, S3 configuration problems, CloudFront errors, and eventually discovered that I had accidentally configured CloudFront to look for:

index.html/index.html
Enter fullscreen mode Exit fullscreen mode

This is the story of how I built it, broke it, debugged it, and finally understood what was actually happening.


1. Starting With a Simple HTML Portfolio

I initially created my portfolio using a single:

index.html
Enter fullscreen mode Exit fullscreen mode

I kept the design intentionally simple.

The portfolio contained:

  • Experience
  • Selected Work
  • Skills
  • Education
  • Contact

Some of the projects I included were:

  • BloodBridge — intelligent blood donor matching platform
  • CITYMIND — a digital twin for city decisions
  • IPL Match Winner Prediction
  • Rural Water Monitoring and Transparency System
  • Textile Hub — a B2B network for the textile trade

At this point, everything worked locally.

I could simply open the HTML file in my browser and see the portfolio.

But then I wanted to actually deploy it.


2. Moving to AWS S3

I decided to use Amazon S3 for hosting.

I created an S3 bucket and uploaded my portfolio.

The object looked like:

s3://portfolio-prasanth/index.html
Enter fullscreen mode Exit fullscreen mode

My first assumption was:

"The file is uploaded, so anyone should be able to open it."

That assumption was wrong.

When I tried accessing the website, I received:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
</Error>
Enter fullscreen mode Exit fullscreen mode

3. First Struggle — S3 AccessDenied

This was my first real AWS deployment problem.

The HTML itself wasn't the issue.

The problem was with S3 permissions and website access configuration.

I had to understand the relationship between:

S3 Bucket
    ↓
Object
    ↓
Permissions
    ↓
Static Website Hosting
Enter fullscreen mode Exit fullscreen mode

I configured static website hosting and worked through the public-access configuration and bucket policy.

The important part of the bucket policy was allowing public GetObject access:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::portfolio-prasanth/*"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

But then I ran into another issue.


4. My Bucket Name Wasn't What I Thought

At one point I was working with:

prasanth-portfolio-bucket
Enter fullscreen mode Exit fullscreen mode

But when I looked at my AWS console, the actual bucket I was configuring was:

portfolio-prasanth
Enter fullscreen mode Exit fullscreen mode

That caused confusion while creating the bucket policy.

AWS was telling me:

Policy has invalid resource
Enter fullscreen mode Exit fullscreen mode

The reason was simple.

The policy resource has to reference the actual bucket name.

So:

arn:aws:s3:::portfolio-prasanth/*
Enter fullscreen mode Exit fullscreen mode

instead of:

arn:aws:s3:::prasanth-portfolio-bucket/*
Enter fullscreen mode Exit fullscreen mode

That was a small mistake, but it taught me something important:

Don't blindly copy AWS configuration. Understand what resource you're actually configuring.


5. Understanding the Static Portfolio Structure

Since my portfolio is a single self-contained index.html — HTML, CSS, and JavaScript all in one file, with a small canvas animation in the hero section — there was no build step involved. No npm run build, no dist/ folder, no bundler.

That turned out to be both a simplification and a lesson in itself:

index.html
     ↓
AWS S3
Enter fullscreen mode Exit fullscreen mode

The browser doesn't need a server running to interpret my markup — it just needs a place that can serve the file over HTTP. S3 static website hosting does exactly that.


6. Adding CloudFront

Then I wanted to put CloudFront in front of S3, mainly to get HTTPS and a CDN in front of the site rather than hitting the S3 website endpoint directly.

The architecture became:

                    ┌──────────────┐
                    │    Browser   │
                    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
                    │  CloudFront  │
                    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
                    │      S3      │
                    │   index.html │
                    └──────────────┘
Enter fullscreen mode Exit fullscreen mode

This was the point where things got interesting.


7. The CloudFront 404 Error

Instead of my portfolio, CloudFront returned:

404 Not Found

Code: NoSuchKey

Message: The specified key does not exist.

Key: index.html/index.html
Enter fullscreen mode Exit fullscreen mode

At first I had no idea why AWS was asking for:

index.html/index.html
Enter fullscreen mode Exit fullscreen mode

My S3 bucket clearly contained:

index.html
Enter fullscreen mode Exit fullscreen mode

not:

index.html/index.html
Enter fullscreen mode Exit fullscreen mode

So I started looking at the CloudFront configuration.


8. Finding the Actual Problem

I checked the CloudFront origin configuration.

And there it was.

My origin looked like:

Origin type: S3 static website
Origin path: /index.html
Enter fullscreen mode Exit fullscreen mode

That was the mistake.

CloudFront already knew that the default root object was:

index.html
Enter fullscreen mode Exit fullscreen mode

And I had also told the origin to use:

/index.html
Enter fullscreen mode Exit fullscreen mode

So CloudFront effectively ended up requesting:

/index.html/index.html
Enter fullscreen mode Exit fullscreen mode

S3 obviously couldn't find that object.

The error suddenly made sense.


9. The Fix

I changed the CloudFront origin path from:

/index.html
Enter fullscreen mode Exit fullscreen mode

to:

(empty)
Enter fullscreen mode Exit fullscreen mode

And kept the CloudFront default root object as:

index.html
Enter fullscreen mode Exit fullscreen mode

So the configuration became conceptually:

CloudFront

Default root object:
index.html

Origin:
portfolio-prasanth S3 website endpoint

Origin path:
(empty)
Enter fullscreen mode Exit fullscreen mode

Now the request flow made sense:

/
 ↓
CloudFront
 ↓
index.html
 ↓
S3
 ↓
portfolio
Enter fullscreen mode Exit fullscreen mode

instead of:

/
 ↓
CloudFront
 ↓
index.html
 ↓
/index.html
 ↓
index.html/index.html ❌
Enter fullscreen mode Exit fullscreen mode

10. Why I Had to Invalidate CloudFront

Even after fixing the configuration, CloudFront can still have cached responses.

So I created a CloudFront invalidation:

/*
Enter fullscreen mode Exit fullscreen mode

This tells CloudFront to remove the cached objects so that the next request can fetch the updated content.


11. What I Actually Learned

The biggest thing I learned from this wasn't HTML or CSS.

It wasn't even CloudFront.

It was debugging.

Before this, when something didn't work, my first instinct was often:

"The code must be wrong."

But this project showed me that problems can exist at completely different layers.

For example:

Frontend
   ↓
Static files
   ↓
S3
   ↓
Permissions
   ↓
CloudFront
   ↓
Caching
   ↓
Browser
Enter fullscreen mode Exit fullscreen mode

A website can have perfectly valid markup and still return a 404 because the infrastructure configuration is wrong.


12. My Struggles

These were some of the problems I faced:

S3

AccessDenied
Enter fullscreen mode Exit fullscreen mode

I had to understand bucket permissions and public access.

Bucket policy

Policy has invalid resource
Enter fullscreen mode Exit fullscreen mode

I was referencing the wrong bucket name.

CloudFront

NoSuchKey
Key: index.html/index.html
Enter fullscreen mode Exit fullscreen mode

I had incorrectly configured the origin path.

Account verification

Before I could even create a CloudFront distribution, AWS returned:

Your account must be verified before you can add new CloudFront resources.
Enter fullscreen mode Exit fullscreen mode

New AWS accounts sometimes need manual verification through AWS Support before CloudFront resources can be created — a step I hadn't expected as part of "just hosting a webpage."

Caching

Even after fixing the configuration, CloudFront could still serve an old cached response.


13. What I Would Do Differently Next Time

If I were starting this deployment again, my process would be:

1. Write and test the portfolio locally
        ↓
2. Upload index.html to S3
        ↓
3. Configure S3 static website hosting + bucket policy
        ↓
4. Verify AWS account (if needed) before touching CloudFront
        ↓
5. Configure CloudFront origin correctly the first time
        ↓
6. Test CloudFront
        ↓
7. Check logs/errors if something fails
        ↓
8. Invalidate cache when required
Enter fullscreen mode Exit fullscreen mode

And most importantly:

I would change one configuration at a time and test after each change.


14. Final Architecture

The final concept I learned is:

                 ┌───────────────────┐
                 │       User        │
                 └─────────┬─────────┘
                           │
                           ▼
                 ┌───────────────────┐
                 │     CloudFront    │
                 │       CDN         │
                 └─────────┬─────────┘
                           │
                           ▼
                 ┌───────────────────┐
                 │    S3 Bucket      │
                 │                   │
                 │   index.html      │
                 └───────────────────┘
Enter fullscreen mode Exit fullscreen mode

My portfolio is a single static file, served through AWS infrastructure and a CDN in front of it.


Final Thoughts

This was a relatively small project, but it gave me something more valuable than just a portfolio.

It gave me experience with the uncomfortable part of development:

things not working.

I had to read errors, inspect configuration, understand what AWS was actually doing, find the mismatch, and fix it.

The index.html/index.html error in particular was frustrating at first.

But once I understood why it happened, it became one of the most useful lessons from the project.

I'm still learning AWS, machine learning, and software development, but I'm slowly trying to replace:

"Copy the config and hope it works"

with:

"Understand what each component is doing, then debug when it doesn't."

And I think that's a much better way to learn.


Tech Stack

Frontend

  • HTML
  • CSS
  • JavaScript

Cloud

  • Amazon S3
  • Amazon CloudFront

Background

  • Python, PyTorch, TensorFlow, Scikit-learn
  • React, TypeScript, Supabase

Development

  • VS Code
  • Git/GitHub

aws #cloudfront #s3 #webdevelopment #javascript #beginners #devjourney #learninginpublic




Top comments (0)