DEV Community

KIRANSARATHI K
KIRANSARATHI K

Posted on

Day1-Cloud Workshop

Permissions

Static Website Hosting

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:::kiran-2403717674421023-15092026/
"
}
]
}

But then I ran into another issue.

  1. My Bucket Name Wasn't What I Thought

At one point I was working with:

kiransarathi k-bucket-portfolio

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

portfolio-nith

That caused confusion while creating the bucket policy.

AWS was telling me:

Policy has invalid resource

The reason was simple.

The policy resource has to reference the actual bucket name.

So:

arn:aws:s3:::kiran-2403717674421023-15092026/*

instead of:

arn:aws:s3:::kiran-2403717674421023-15092026/*

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

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

  1. Then I Wanted to Use React

Once I had the basic portfolio working, I decided to convert it into a React application.

Instead of one large HTML file, I moved to a React + Vite structure:

portfolio/

├── index.html
├── package.json

└── src/
├── main.jsx
└── style.css

I used React to render the portfolio sections and JavaScript arrays for things like skills and projects.

For example:

const skills = [
"Python",
"C / C++",
"Data Structures & Algorithms",
"Machine Learning",
"TensorFlow",
"NumPy",
"Pandas",
"Docker"
];

And projects were represented as data:

const projects = [
{
title: "CLOTE",
description: "...",
tech: "Private Cloud • File Management"
}
];

This was my first step toward understanding how a real frontend project is structured rather than putting everything into one HTML file.

  1. Understanding npm run build

This was another important part.

I initially thought:

"Since it's React, I need a server running on AWS."

Not necessarily.

React can be built into static files.

I ran:

npm install

and then:

npm run build

Vite generated:

dist/

├── index.html
└── assets/
├── ...
└── ...

This was a major realization for me.

The browser doesn't need my React source code or Node.js running on S3.

The production build becomes static assets that can be served by a web server.

So the deployment becomes:

React source

npm run build

dist/

AWS S3

  1. Adding CloudFront

Then I wanted to put CloudFront in front of S3.

The architecture became:

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

This was the point where things got interesting.

  1. 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

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

index.html/index.html

My S3 bucket clearly contained:

index.html

not:

index.html/index.html

So I started looking at the CloudFront configuration.

  1. 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

That was the mistake.

CloudFront already knew that the default root object was:

index.html

And I had also told the origin to use:

/index.html

So CloudFront effectively ended up requesting:

/index.html/index.html

S3 obviously couldn't find that object.

The error suddenly made sense.

  1. The Fix

I changed the CloudFront origin path from:

/index.html

to:

(empty)

And kept the CloudFront default root object as:

index.html

So the configuration became conceptually:

CloudFront

Default root object:
index.html

Origin:
portfolio-nith S3 website endpoint

Origin path:
(empty)

Now the request flow made sense:

/

CloudFront

index.html

S3

portfolio

instead of:

/

CloudFront

index.html

/index.html

index.html/index.html ❌

  1. Why I Had to Invalidate CloudFront

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

So I created a CloudFront invalidation:

/*

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

  1. What I Actually Learned

The biggest thing I learned from this wasn't React.

It wasn't S3.

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

React

Build

Static files

S3

Permissions

CloudFront

Caching

Browser

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

  1. My Struggles

These were some of the problems I faced:

S3

AccessDenied

I had to understand bucket permissions and public access.

Bucket policy

Policy has invalid resource

I was referencing the wrong bucket name.

CloudFront

NoSuchKey
Key: index.html/index.html

I had incorrectly configured the origin path.

Caching

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

  1. What I Would Do Differently Next Time

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

  1. Build React application ↓
  2. Test locally ↓
  3. npm run build ↓
  4. Check dist/ ↓
  5. Upload dist contents to S3 ↓
  6. Configure S3 ↓
  7. Configure CloudFront ↓
  8. Test CloudFront ↓
  9. Check logs/errors if something fails ↓
  10. Invalidate cache when required

And most importantly:

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

  1. Final Architecture

The final concept I learned is:

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

My React application is built into static files and served through AWS infrastructure.

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, React, and software development, but I'm slowly trying to replace:

"Copy the code 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 development.

Tech Stack

Frontend

React

Vite

HTML

CSS

JavaScript

Cloud

Amazon S3

Amazon CloudFront

Development

VS Code

npm

Git/GitHub






Top comments (0)