Host a Static Website on S3
Learn to host a static website on S3 with this hands-on AWS tutorial. We'll cover the core concept, step-by-step setup, practical walkthrough, troubleshooting, and what to learn next.
Focus: host a static website on s3
You've built a beautiful static site — maybe a landing page, a portfolio, or documentation for your Python project — and now you need to put it on the internet. You could spin up an EC2 instance, install nginx, and babysit a server, but that's overkill and costs money 24/7. The pain is real: you want something fast, cheap, and reliable, without managing infrastructure. The solution is hosting a static website on Amazon S3 — a service that stores your files and serves them to the world with incredible durability and near-zero cost. In this lesson, you'll learn exactly how to do it, step by step, and you'll have your site live by the end.
The problem this lesson solves
Traditional web hosting requires a server. A server means an operating system, security patches, a web server like Apache or nginx, and someone to keep it running. For a static website — where every visitor sees the same HTML, CSS, and JavaScript files — that's a massive waste of time and money. You pay for compute you don't need, and you worry about uptime, DDoS attacks, and scaling. Hosting a static website on S3 eliminates all that: S3 stores your files as objects, serves them over HTTP, and scales automatically to any number of visitors. You don't provision anything; you just upload files and configure a few settings.
Core concept / mental model
Think of S3 as a giant, internet-connected hard drive. Each bucket is a folder, and each file inside is an object. Normally, objects are private and accessed via APIs, but you can turn on static website hosting for a bucket, which makes it behave like a simple web server. When you configure the bucket for web hosting, S3 gives you a website endpoint like http://my-bucket.s3-website-us-east-1.amazonaws.com. Any object you upload becomes a publicly accessible web page, and S3 automatically looks for an index.html file to serve as the homepage.
The bucket itself acts as the root directory. The key insight: you're not running a server; S3 is the server. It handles HTTP requests, serves your files, and returns error documents (like a custom 404.html). The only 'configuration' you do is enabling the feature and setting permissions — the rest is magic.
How it works step by step
- Create a bucket — Choose a globally unique name, select a region (e.g.,
us-east-1), and keep all other defaults. The bucket name will appear in your URL, so pick something readable. - Upload your website files — These are the HTML, CSS, JS, images, etc. You can upload them one at a time or use the AWS CLI to sync a local folder.
- Enable static website hosting — In the bucket's Properties tab, configure the index document (e.g.,
index.html) and error document (e.g.,404.html). - Set public access permissions — By default, S3 blocks public access. You need to disable 'Block all public access' and attach a bucket policy that gives
s3:GetObjectpermission to everyone. - Test your endpoint — S3 provides a website endpoint; visit it in a browser to confirm your site loads.
- (Optional) Add a custom domain — Use Route 53 or another DNS provider to point your domain to the S3 endpoint.
Hands-on walkthrough
Let's make it real. You'll need an AWS account and the AWS CLI configured. We'll create a simple portfolio site with two files and host it.
Step 1: Create a simple website
First, create two files locally: index.html and 404.html.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head><title>My S3 Site</title></head>
<body>
<h1>Hello from S3! 🚀</h1>
<p>This page is served from an S3 bucket.</p>
</body>
</html>
<!-- 404.html -->
<!DOCTYPE html>
<html>
<head><title>404 Not Found</title></head>
<body>
<h1>Page not found</h1>
<p>Sorry, this page doesn't exist.</p>
</body>
</html>
Step 2: Create the bucket and upload files using the AWS CLI
Open a terminal and run these commands (replace my-unique-bucket-name with something like my-portfolio-2025):
# Create the bucket (region us-east-1)
aws s3 mb s3://my-unique-bucket-name --region us-east-1
# Upload the files
aws s3 cp index.html s3://my-unique-bucket-name/
aws s3 cp 404.html s3://my-unique-bucket-name/
Step 3: Enable static website hosting
Use the AWS CLI to enable the website configuration:
aws s3 website s3://my-unique-bucket-name \
--index-document index.html \
--error-document 404.html
Step 4: Set public access
You must (a) disable the bucket's Public Access Block and (b) attach a bucket policy. Here's a policy you can save as policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-unique-bucket-name/*"
}
]
}
Apply it with:
# Disable the public access block (via CLI)
aws s3api put-public-access-block --bucket my-unique-bucket-name \
--public-access-block-configuration BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
# Attach the bucket policy
aws s3api put-bucket-policy --bucket my-unique-bucket-name \
--policy file://policy.json
Step 5: Test it
Find your website endpoint (in the S3 console under Properties → Static website hosting). It should look like http://my-unique-bucket-name.s3-website-us-east-1.amazonaws.com. Open it in a browser — you'll see your index.html page. Try a random path like /nope and you'll get your 404.html.
Pro tip: Use
aws s3 syncinstead ofcpto upload your site folder. It only transfers changed files, which is a huge time-saver when you update content.
Compare options / when to choose what
Hosting a static website on S3 is not the only option. Here's how S3 compares to other common approaches:
| Option | Best for | Pros | Cons |
|---|---|---|---|
| S3 static hosting | Static sites (HTML/CSS/JS) | Cheap, scalable, zero maintenance | No server-side scripting; custom HTTPS requires CloudFront |
| EC2 + nginx | Dynamic sites, full control | Full control, can run any stack | Requires patching, scaling, and 24/7 cost |
| CloudFront + S3 | Global edge delivery + HTTPS | Fast, HTTPS, CDN benefits | Slightly more setup, small extra cost |
When to choose S3-only: If your site is purely static and you don't need HTTPS (or are okay using the HTTP endpoint for testing), S3 is your best friend. When to add CloudFront: If you need SSL (recommended for any public website) or want to serve content globally faster, put CloudFront in front of S3. You'll learn more about that in a later lesson.
Troubleshooting & edge cases
- 403 Forbidden on the endpoint: Your bucket policy is missing or the public access block is still enabled. Verify the policy allows
s3:GetObjectforPrincipal: "*"and that all four public access block settings are disabled. - 404 when accessing the root: Ensure you have an
index.htmlfile in the bucket root. S3 won't serve a directory listing; it only serves the index document you specified. - Custom domain not resolving: DNS takes time to propagate. Also, the S3 website endpoint must match the region where your bucket lives. For custom domains, you must use a bucket name identical to your domain (e.g.,
www.example.com) if you're not using CloudFront. - HTTPS not available: S3 website endpoints only support HTTP. To get HTTPS, you must use CloudFront (or another CDN). This is a common gotcha.
- Bucket name already taken: S3 bucket names are globally unique. Choose a more specific name or append a number.
What you learned & what's next
You now understand the core idea behind hosting a static website on S3 and have completed a practical exercise: you created a bucket, uploaded files, enabled website hosting, set permissions, and saw your site live. You also learned when to choose S3 over other options and how to troubleshoot the most common issues.
This is a foundational skill for deploying any static frontend. Next up in the track, we'll explore CloudFront to add a Content Delivery Network, custom domains with HTTPS, and cache behaviors — making your S3-hosted site production-ready. You'll take everything you just built and supercharge it with edge caching and SSL. Stay tuned!
Practice recap
As a hands-on exercise, create a small one-page site for a hypothetical app (like a Python package landing page) and host it on S3 using the CLI. Then, access the website endpoint to verify it works, and try intentionally breaking the policy to see the 403 error — then fix it. This will cement the troubleshooting steps.
Common mistakes
- Forgetting to disable 'Block all public access' — even with a correct bucket policy, you'll get 403 Forbidden.
- Creating a bucket with a name that's already taken; S3 names are globally unique, so add a unique suffix.
- Uploading files but not setting the index document — the site shows 404 at the root.
- Using the S3 REST API endpoint (e.g.,
s3.amazonaws.com) instead of the website endpoint — the API doesn't serve HTML content correctly.
Variations
- Use the AWS Management Console instead of the CLI — it's a guided point-and-click alternative for visual learners.
- Add a CDN (CloudFront) in front of S3 to enable HTTPS and faster global delivery — recommended for production.
- Use a static site generator (Hugo, Gatsby, or plain Python with Jinja) to build your site locally, then sync the output to S3.
Real-world use cases
- Hosting a personal portfolio or resume site with a custom domain and no server costs.
- Deploying documentation for an open-source Python library (auto-generated with MkDocs) as a versioned S3 site.
- Serving a static marketing landing page for a startup, with A/B testing via CloudFront and S3.
Key takeaways
- S3 static website hosting turns a bucket into a simple web server for HTML/CSS/JS with zero compute.
- You must explicitly enable website hosting and set index/error documents in the bucket properties.
- Public read access requires both disabling the bucket public access block and attaching a policy allowing s3:GetObject for everyone.
- The website endpoint is HTTP-only; for HTTPS you need CloudFront.
- Use
aws s3 syncfor efficient uploads — it only transfers changed files. - S3 is ideal for static sites; choose EC2 for dynamic content and CloudFront for global + HTTPS.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.