Solomon Wilson · IT Solowils

Host a Website on Amazon S3

Put your first website on the internet using nothing but a storage bucket.

0 of 8 steps complete

DifficultyEasy
Time45 min
UpdatedNov 2026
CostUnder $0.05
OSAny browser
ServiceAmazon S3

Related projects

Create an AWS account Next: HTTPS with CloudFront (coming soon)

The 30-second version

stores files of any size and hands them back to anyone you allow, from anywhere.

A simple website is only a handful of files. Put those files in an S3 bucket, switch on , give the public permission to read them, and S3 serves them as a website. No server to build or patch.

Project architecture Your website files are uploaded into an S3 bucket with static website hosting switched on. A bucket policy allows public reads, and visitors load the site from the bucket website endpoint over HTTP. Website files index.html · error.html · assets/ S3 bucket static website hosting on bucket policy: public read Visitor's browser upload GET over HTTP
What you'll build today

Why start here?

Static hosting on S3 is the smallest real cloud deployment you can make. You will meet three ideas that come up in almost every AWS project after this one: buckets and objects, public access controls, and policies written in JSON.

Go to end

Start your project here

Pick how much help you want. You can switch at any time and your progress stays put.

How this page works

Each step ends with an evidence task: a screenshot plus a sentence or two in your own words. Tick Mark step as complete as you go. When you finish, open My record to print or save a PDF of your work for your portfolio. Nothing is uploaded anywhere; it all stays in this browser.

Step 0

Before we start

✓ Complete

In this step, get ready to:

  • Check you have what you need.
  • Choose the AWS Region you will work in.
  • Know what this project will cost (very little).

What you need

  • An AWS account. If you don't have one yet, follow the AWS guide linked under Related projects.
  • A sign-in that isn't the root user. An IAM Identity Center user or an IAM user with S3 permissions is the safer habit.
  • A computer with a modern browser and a way to unzip files.

What it costs

A few small files and a handful of page views cost a fraction of a US cent. Accounts opened after 15 July 2025 also start on the AWS Free plan with sign-up credits. The only way this gets expensive is forgetting the bucket for months, which is why the last step deletes everything.

Pick a Region

A Region is a cluster of AWS data centres in one part of the world. Your bucket lives in exactly one. Any Region works for this project; one close to your visitors loads a little faster.

Learning from West Africa?

Africa (Cape Town), af-south-1, is an opt-in Region, so it has to be enabled in your account settings before it appears. If you'd rather not, Europe (London) eu-west-2 or Europe (Ireland) eu-west-1 are fine choices.

Evidence: your starting point

To do

In a sentence or two: which Region did you choose, and why?

Your screenshot for Step 0
Step 1

Create an S3 bucket

✓ Complete

Every file in S3 lives inside a bucket. Yours will hold the whole website.

In this step, get ready to:

  • Open Amazon S3 in the AWS console.
  • Create a general purpose bucket with a name nobody else in the world is using.
  • Allow public access for this one bucket.

We use it to build your bucket name and to put on your completion record. It never leaves this browser.

Your bucket name:

Bucket name
itsolowils-s3-site-yourname-abcd

The four characters at the end are random and saved for you, so two learners with the same name won't clash.

Key settings

  • Bucket type: General purpose
  • Object Ownership: ACLs disabled (recommended)
  • Block all public access: cleared, with the warning acknowledged
  • Bucket Versioning: Disable · Default encryption: leave as it is
  1. Sign in to the AWS Management Console.
  2. In the search bar at the top, type S3 and choose S3.
  3. Check the Region selector in the top-right corner and switch it to the Region you picked in Step 0.
  4. Choose Create bucket.
  5. If you're asked for a Bucket type, keep General purpose.
  6. Paste your bucket name from the box above into Bucket name.
  7. Under Object Ownership, leave ACLs disabled (recommended) selected.
  8. Under Block Public Access settings for this bucket, clear the Block all public access checkbox.
    • A warning appears. Tick the box that acknowledges the bucket and its objects might become public. For a website, that is the point.
  9. Leave Bucket Versioning on Disable and the encryption settings as they are.
  10. Scroll down and choose Create bucket. Your bucket appears in the list.

Public buckets are for public files only

Turning off Block Public Access on this bucket is fine because everything in it is meant for the whole internet. Never do this on a bucket holding backups, reports or anything personal.

Why does the name have to be unique?

Bucket names share one namespace across every AWS account, because the name becomes part of a web address. Once you own itsolowils-s3-site-…, nobody else can create a bucket with that name until you delete yours. Names must be 3 to 63 characters of lowercase letters, numbers, hyphens and dots.

What is Block Public Access protecting me from?

Block Public Access is a safety switch that overrides any rule granting public access, even if someone writes one by mistake. It is on by default for every new bucket. Clearing it doesn't make anything public by itself. It only allows a public rule to work. You'll write that rule in Step 4.

Why leave ACLs disabled?

Access control lists are an older way of granting permissions file by file. AWS now recommends leaving them off and controlling access with one bucket policy instead. It's easier to read, easier to audit and covers every object at once.

🛠 Troubleshooting: the console won't accept my bucket name
  • "Bucket with the same name already exists": someone, somewhere, owns it. Change the last four characters and try again.
  • "Bucket name must not contain uppercase characters": lowercase only, no spaces or underscores.

Evidence: your new bucket

To do

Screenshot the bucket list showing your bucket and its Region. Then explain, in your own words, what Block Public Access does.

Your screenshot for Step 1
Step 2

Upload your website files

✓ Complete

An empty bucket isn't much of a website. Time to fill it.

In this step, get ready to:

  • Download the starter website and make it yours.
  • Upload its files into your bucket as objects.

Download starter-site.zip (2 KB)

Inside you'll find index.html, error.html and an assets folder with a stylesheet and an icon.

Key settings

  • Upload index.html and error.html with Add files.
  • Upload the assets folder with Add folder, so the keys start with assets/.
  • All three should sit at the top level of the bucket, not inside starter-site/.
  1. Unzip starter-site.zip. You get a folder called starter-site.
  2. Optional but worth it: open index.html in a text editor (Notepad, TextEdit, VS Code), change Your Name in the heading to your name, and save.
  3. Back in the S3 console, choose your bucket's name to open it.
  4. On the Objects tab, choose Upload.
  5. Choose Add files and select index.html and error.html from inside the starter-site folder.
  6. Choose Add folder and select the assets folder. Confirm if your browser asks whether to upload its files.
  7. Check the list: you should see index.html, error.html, assets/style.css and assets/cloud.svg.
  8. Choose Upload, wait for the green success banner, then choose Close.

Hot tip for Windows users

Windows sometimes unzips into a folder inside a folder with the same name. If you open starter-site and find another starter-site, go one level deeper before you pick your files.

Wait, S3 has folders?

Not really. S3 is flat: every object has a key, which is just its full name, like assets/style.css. The console draws a folder whenever a key contains a slash, so it looks familiar. This matters in Step 4: if you upload the whole starter-site folder, your homepage's key becomes starter-site/index.html and S3 won't find it at the top.

What do HTML and CSS actually do?

HTML describes what's on a page: headings, paragraphs, images, links. CSS describes how it looks: colours, fonts, spacing. A browser downloads both and puts the page together. Because nothing has to run on the server, the site is called static.

Evidence: your objects

To do

Screenshot the Objects tab showing index.html, error.html and the assets/ folder. Note what you changed in index.html, if anything.

Your screenshot for Step 2
Step 3

Turn on static website hosting

✓ Complete

Bucket: done. Files: done. Now tell S3 to treat the bucket as a website.

In this step, get ready to:

  • Switch on static website hosting with an index and an error document.
  • Find your bucket's website endpoint and open it.
  • Meet your first error, on purpose.

Key settings

  • Properties tab → Static website hosting → Edit
  • Enable · Host a static website
  • Index document index.html · Error document error.html
  1. Inside your bucket, choose the Properties tab.
  2. Scroll all the way down to the Static website hosting panel and choose Edit.
  3. Set:
    • Static website hosting: Enable
    • Hosting type: Host a static website
    • Index document: index.html
    • Error document: error.html
  4. Choose Save changes.
  5. Scroll back down to Static website hosting. Under Bucket website endpoint, open the link in a new tab.

Your endpoint looks like one of these, depending on the Region:

Website endpoint formats
http://bucket-name.s3-website-region.amazonaws.com
http://bucket-name.s3-website.region.amazonaws.com

403 Forbidden? Good.

You should see 403 Forbidden with the code AccessDenied. Keep that tab open. It proves the website is switched on but nobody has been given permission to read your files yet.

Why do I get 403 Forbidden?

Everything in S3 is private until a rule says otherwise. In Step 1 you removed the safety switch that blocks public rules, but you haven't written a rule that allows anything. Think of a shop with the shutters up and the door still locked. Step 4 unlocks the door.

What's special about the website endpoint?

S3 has two ways in. The normal endpoint lists and fetches objects for programs. The website endpoint behaves like a web server: it returns index.html when someone visits the root, serves error.html when a page is missing, and supports redirects. It only speaks plain HTTP, which is why your browser may label it "Not secure". Adding HTTPS with CloudFront is the next project.

Evidence: the 403 error

To do

Screenshot the 403 Forbidden page with the address bar visible. Explain why it happens.

Your screenshot for Step 3
Step 4

Go public with a bucket policy

✓ Complete

One small JSON document stands between you and a live website.

In this step, get ready to:

  • Write a bucket policy that lets anyone read your files.
  • Refresh the 403 tab and see your website live.
Bucket policy · public read
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForWebsite",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::itsolowils-s3-site-yourname-abcd/*"
    }
  ]
}

Your bucket name is already filled in. If you changed it in the console, edit the Resource line to match.

Write a policy that allows everyone to perform s3:GetObject on every object in your bucket, then attach it under Permissions → Bucket policy.

Reveal the policy if you need it
Bucket policy · public read
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForWebsite",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::itsolowils-s3-site-yourname-abcd/*"
    }
  ]
}

Want to find the policy editor yourself first?

Good call. Hint: permissions live on a tab with a very obvious name. Come back and open the clicks if you get lost.

  1. Switch to the S3 console tab and open your bucket.
  2. Choose the Permissions tab.
  3. In the Bucket policy panel, choose Edit.
  4. Copy the policy above and paste it into the editor, replacing anything already there.
  5. Choose Save changes. The bucket now shows a Publicly accessible badge.
  6. Go back to the tab showing 403 Forbidden and refresh.

It's alive

Refresh the endpoint tab. Your page appears, styled and with your name on it. Share the link with a friend and it will work for them too.

Read the policy line by line
  • "Version": "2012-10-17" is the policy language version. It's a fixed value, not today's date.
  • "Effect": "Allow" means this statement grants permission.
  • "Principal": "*" means anyone, including people who aren't signed in to AWS.
  • "Action": "s3:GetObject" allows reading (downloading) objects and nothing else. Visitors can't upload, list or delete.
  • "Resource": "arn:aws:s3:::bucket/*" is the ARN for every object in the bucket. The /* matters: without it the rule points at the bucket itself, not the files inside.
Bucket policies vs ACLs

A bucket policy is one document that governs the whole bucket, so you can read every permission in one place. ACLs attach a permission to each object, which is easy to lose track of. That's why new buckets come with ACLs disabled and AWS points you to policies instead.

🛠 Troubleshooting: it still doesn't work
  • "Policy has invalid resource" when saving: the bucket name in Resource doesn't match your bucket, or the /* is missing.
  • "Access denied" when saving: Block Public Access is still on, either for this bucket (Permissions tab) or for your whole account (S3 menu → Block Public Access settings for this account).
  • 404 Not Found, Code: NoSuchKey: S3 can't find index.html at the top of the bucket. Check the spelling in Step 3 and that you didn't upload the whole starter-site folder. Fix it by uploading index.html again at the top level.
  • The page loads but looks plain: the assets folder didn't upload, so the stylesheet is missing.
  • Still 403 after saving: hard refresh with Ctrl + F5 (Windows) or Cmd + Shift + R (Mac), and make sure you're on the website endpoint from Step 3.
  • Browser says "Not secure": expected. Website endpoints are HTTP only.

Evidence: your live website

To do

Screenshot your live site with the endpoint visible in the address bar. In one sentence, what does "Principal": "*" mean?

Your screenshot for Step 4
Secret mission

Protect your homepage from deletion

✓ Complete

Optional, and the best part. You'll make it impossible to delete index.html, even for yourself, then prove it.

In this mission, get ready to:

  • Add a Deny statement to your bucket policy.
  • Try to delete index.html and watch it fail.
  • Explain why an explicit deny always wins.
Bucket policy · public read + protect index.html
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForWebsite",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::itsolowils-s3-site-yourname-abcd/*"
    },
    {
      "Sid": "ProtectHomepage",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:DeleteObject",
      "Resource": "arn:aws:s3:::itsolowils-s3-site-yourname-abcd/index.html"
    }
  ]
}

Add a second statement to your policy that denies s3:DeleteObject to everyone on index.html only. Then try deleting it.

  1. Open Permissions → Bucket policy → Edit.
  2. Replace the policy with the two-statement version above and choose Save changes.
  3. Go to the Objects tab, tick index.html and choose Delete.
  4. Type permanently delete to confirm and choose Delete objects.
  5. The console reports that the delete failed with an access denied error. Mission accomplished.
Why does Deny beat my admin permissions?

AWS checks every request against all the policies that apply. An explicit Deny anywhere overrides every Allow, no matter how powerful. That's what makes Deny statements useful as guardrails: they protect critical files from mistakes, including your own. Your account can still edit or remove the bucket policy itself, which is how you'll undo this in the next step.

Evidence: the failed delete

To do

Screenshot the failed delete. Where else at work could a Deny guardrail like this be useful?

Your screenshot for the secret mission
Before you go

Delete your resources

✓ Complete

Cleaning up is part of the job on every project. It keeps your bill at zero and takes a public bucket off the internet.

In this step, get ready to:

  • Remove the bucket policy.
  • Empty the bucket.
  • Delete the bucket.

Think you can do this without instructions?

Great. Double-check the General purpose buckets list: your bucket should be gone.

  1. Open your bucket → Permissions → Bucket policy → Delete. Type delete to confirm. This removes the Deny rule from the secret mission.
  2. Go back to General purpose buckets, select your bucket and choose Empty.
  3. Type permanently delete and choose Empty, then Exit.
  4. With the bucket still selected, choose Delete.
  5. Type your bucket name to confirm and choose Delete bucket.
🛠 Troubleshooting: index.html won't delete

That's the secret mission doing its job. Delete the bucket policy first (step 1 above), then empty the bucket again.

Evidence: clean account

To do

Screenshot your bucket list without the project bucket. Why did you have to empty the bucket before deleting it?

Your screenshot for Step 6
Finish line

You just shipped a website on AWS

✓ Complete

Well done.

That wasn't nothing. You took a folder of files and made it a public website using cloud storage alone. Along the way you:

  • Created an S3 bucket with a globally unique name.
  • Uploaded HTML, CSS and image files as objects.
  • Switched on static website hosting with index and error documents.
  • Wrote a bucket policy to grant public read access, and a Deny rule to protect a file.
  • Cleaned up every resource you created.
More projects

Does the dock say you still have tasks left?

Open My record. Anything without a note or screenshot, or flagged Return to later, is listed there with a link straight to it.

Join the live feed

Finished? Put your first name and country on the homepage feed. Completely optional.