How to Host Static Site on S3
How to Host a Static Site on S3 Hosting a static website on Amazon S3 (Simple Storage Service) is one of the most cost-effective, scalable, and reliable ways to deploy modern web applications. Whether you're building a personal portfolio, a marketing landing page, a documentation hub, or a React/Vue/Angular single-page application (SPA), S3 provides a serverless infrastructure that eliminates the
How to Host a Static Site on S3
Hosting a static website on Amazon S3 (Simple Storage Service) is one of the most cost-effective, scalable, and reliable ways to deploy modern web applications. Whether you're building a personal portfolio, a marketing landing page, a documentation hub, or a React/Vue/Angular single-page application (SPA), S3 provides a serverless infrastructure that eliminates the need for managing servers, patching software, or configuring load balancers. With just a few clicks and a basic understanding of AWS services, you can have your static site live on the global AWS network with sub-second latency, automatic scaling, and enterprise-grade security.
The rise of static site generators like Jekyll, Hugo, Gatsby, and Next.js has made it easier than ever to build fast, secure, and SEO-friendly websites without relying on backend databases or dynamic server-side rendering. S3 is the natural hosting partner for these tools, offering persistent storage, customizable access controls, and seamless integration with CloudFront for content delivery and SSL encryption.
In this comprehensive guide, you’ll learn exactly how to host a static site on S3—from preparing your files to configuring permissions, enabling HTTPS, optimizing performance, and troubleshooting common issues. By the end, you’ll have a fully functional, production-ready static website hosted on AWS, optimized for speed, security, and search engine visibility.
Step-by-Step Guide
Prerequisites
Before you begin, ensure you have the following:
- An AWS account (free tier eligible)
- A static website (HTML, CSS, JS files, images, etc.)
- A local terminal or command-line interface (CLI)
- Optional: AWS CLI installed and configured
If you don’t have a static site ready, you can create a simple one using a text editor. Create a folder named my-static-site, and inside it, add:
index.html– the homepagestyles.css– for stylingscript.js– for interactivityimages/– folder for assets
Example index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Static Site on S3</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Welcome to My Static Site</h1>
<p>Hosted on Amazon S3.</p>
<script src="script.js"></script>
</body>
</html>
Save all files and ensure they work locally by opening index.html in a browser.
Step 1: Log in to the AWS Management Console
Visit https://aws.amazon.com/console/ and sign in with your AWS credentials. If you don’t have an account, create one. AWS offers a free tier that includes 5 GB of S3 storage and 20,000 GET requests per month—plenty for most small static sites.
Step 2: Navigate to the S3 Service
In the AWS console, use the search bar at the top to type “S3” and select “S3” from the results. This opens the S3 dashboard, where you manage all your storage buckets.
Step 3: Create a New S3 Bucket
Click the “Create bucket” button. You’ll be prompted to enter:
- Bucket name: Must be globally unique across all AWS accounts. Use a name like
my-website-2024orwww.yourdomain.com. Avoid special characters and use lowercase letters, numbers, and hyphens. - Region: Choose the region closest to your target audience for lower latency. For global audiences, consider us-east-1 (N. Virginia) due to its extensive CloudFront edge locations.
Leave all other settings at default unless you have specific compliance or encryption requirements. Click “Create bucket.”
Step 4: Upload Your Website Files
Once your bucket is created, click on its name to enter the bucket management view. Click “Upload” and select all files from your local my-static-site folder. Drag and drop is supported.
After selecting files, scroll down to the “Set permissions” section. Ensure “Block all public access” is unchecked—you need public read access for your site to be viewable online.
Click “Upload.” All files should now appear in the bucket list.
Step 5: Enable Static Website Hosting
With your bucket still open, go to the “Properties” tab. Scroll down to “Static website hosting” and click “Edit.”
Select “Enable” and configure:
- Index document: Enter
index.html - Error document: Enter
index.html(critical for SPAs like React or Vue that use client-side routing)
Click “Save changes.”
After saving, you’ll see a message: “This bucket is configured as a website.” Below it, you’ll find a website endpoint URL—something like:
http://my-website-2024.s3-website-us-east-1.amazonaws.com
Copy this URL and paste it into your browser. If everything is configured correctly, your static site will load.
Step 6: Configure Bucket Policy for Public Access
Even after disabling public access blocking, S3 requires an explicit bucket policy to allow public read access to objects. Go to the “Permissions” tab and scroll to “Bucket policy.”
Click “Edit” and paste the following JSON policy (replace my-website-2024 with your bucket name):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website-2024/*"
}
]
}
Click “Save changes.”
This policy grants any user on the internet permission to read (GET) any object inside your bucket—exactly what you need for a public website.
Step 7: Test Your Site
Visit your website endpoint URL again. You should now see your homepage. If images or styles aren’t loading, check the browser’s developer console (F12) for 404 errors. Common issues include:
- File names with uppercase letters (S3 is case-sensitive)
- Missing trailing slashes in links
- Incorrect file paths in HTML
Ensure all references in your HTML use relative paths (e.g., ./styles.css or images/logo.png) rather than absolute paths pointing to your local machine.
Step 8: Set Correct MIME Types (Optional but Recommended)
S3 automatically detects MIME types based on file extensions, but sometimes it misidentifies files—especially for newer formats like .woff2 or .json. To ensure proper rendering:
- Select a file in the bucket list
- Click “Properties” on the right
- Under “Metadata,” add or edit the
Content-Typekey
Common MIME types:
.css→text/css.js→application/javascript.json→application/json.woff→font/woff.woff2→font/woff2.svg→image/svg+xml
For bulk updates, use the AWS CLI or a tool like aws-s3-static-website (covered later) to automate this process.
Step 9: Use AWS CLI for Automated Deployment (Optional)
Manually uploading files via the console works for small sites, but for regular updates, use the AWS CLI. Install it from https://aws.amazon.com/cli/.
Configure your credentials:
aws configure
Enter your AWS Access Key ID, Secret Access Key, region (e.g., us-east-1), and output format (json).
Then, sync your local folder to the S3 bucket:
aws s3 sync ./my-static-site s3://my-website-2024 --delete
The --delete flag removes files from S3 that no longer exist locally, keeping your deployment clean. This command is ideal for CI/CD pipelines and automation scripts.
Step 10: Add a Custom Domain (Optional)
By default, your site lives under an AWS-generated URL. To use your own domain (e.g., www.yourdomain.com), follow these steps:
- Register a domain through Route 53 or a third-party registrar (Namecheap, GoDaddy, etc.)
- In S3, create a second bucket named exactly after your domain (e.g.,
www.yourdomain.com) - Enable static website hosting on this bucket with the same index and error documents
- Upload your files to this new bucket
- In your domain registrar’s DNS settings, create a CNAME record pointing
www.yourdomain.comto the S3 website endpoint (e.g.,www.yourdomain.com.s3-website-us-east-1.amazonaws.com)
For apex domains (e.g., yourdomain.com), S3 doesn’t support CNAME records directly. Use CloudFront (next section) or redirect from the apex bucket to the www bucket using S3 redirect rules.
Best Practices
Use HTTPS with CloudFront
The S3 website endpoint provides HTTP only. For production sites, you must enable HTTPS. The easiest way is to use Amazon CloudFront, AWS’s content delivery network (CDN).
CloudFront caches your content at edge locations worldwide, improving load times and adding SSL/TLS encryption automatically.
To set it up:
- In the AWS Console, go to CloudFront
- Click “Create distribution”
- Under “Origin domain,” select your S3 bucket’s website endpoint (not the bucket ARN)
- Set “Origin path” to blank
- Under “Viewer protocol policy,” select “Redirect HTTP to HTTPS”
- For “Alternate domain names,” add your custom domain (e.g.,
www.yourdomain.com) - Under “SSL certificate,” choose “Request a certificate with ACM” and follow the validation steps
- Set “Default root object” to
index.html - Click “Create distribution”
Wait 5–15 minutes for the distribution to deploy. Once active, update your DNS CNAME record to point to the CloudFront domain (e.g., d12345.cloudfront.net).
Your site is now served over HTTPS with global caching, improved performance, and better SEO rankings.
Enable Compression
Enable GZIP compression for text-based files (HTML, CSS, JS, JSON) to reduce file sizes and improve load times. S3 doesn’t compress files automatically, but CloudFront can do it on-the-fly.
In your CloudFront distribution settings, under “Origin and Origin Groups,” ensure “Compress Objects Automatically” is set to “Yes.” This reduces bandwidth usage and speeds up delivery without manual preprocessing.
Set Cache Headers
Configure long cache expiration for static assets to reduce server requests and improve performance. Use the AWS CLI or console to set Cache-Control headers on files:
- HTML files:
Cache-Control: max-age=300(5 minutes) - CSS/JS/Images:
Cache-Control: max-age=31536000(1 year)
Use the AWS CLI to set headers during upload:
aws s3 cp ./styles.css s3://my-website-2024/styles.css --cache-control "max-age=31536000" --content-type "text/css"
For bulk operations, use the sync command with metadata:
aws s3 sync ./my-static-site s3://my-website-2024 --delete --cache-control "max-age=31536000" --exclude "*.html" --include "*"
Then separately sync HTML files with a shorter cache:
aws s3 sync ./my-static-site s3://my-website-2024 --delete --cache-control "max-age=300" --include "*.html"
Implement Versioning and Backups
Enable versioning on your S3 bucket to protect against accidental deletions or overwrites. Go to the “Properties” tab of your bucket and toggle “Versioning” to “Enabled.”
While versioning increases storage costs slightly, it provides a safety net. You can also use S3 lifecycle policies to automatically archive older versions to Glacier or delete them after 90 days.
Use IAM Roles for Automation
If you’re deploying via CI/CD (GitHub Actions, Jenkins, CircleCI), avoid using root AWS credentials. Instead, create an IAM user with minimal permissions:
- Policy:
AmazonS3FullAccess(for simplicity) or a custom policy granting onlys3:PutObject,s3:GetObject,s3:DeleteObjecton your specific bucket - Attach the policy to the IAM user
- Store the access key as a secret in your CI tool
This follows the principle of least privilege and improves security.
Monitor and Log Access
Enable server access logging in your S3 bucket to track who accesses your files and when. Go to “Properties” → “Server access logging” → Enable and specify a target bucket for logs.
For advanced monitoring, integrate with Amazon CloudWatch to track metrics like request count, error rates, and data transfer. Set alarms for unusual spikes in traffic or 4xx/5xx errors.
Secure Against Common Threats
- Never store sensitive data (API keys, passwords) in static files
- Use Content Security Policy (CSP) headers in your HTML to prevent XSS
- Validate and sanitize all user inputs if you use forms (submit to external services like Formspree or Netlify Forms)
- Regularly audit bucket policies to ensure no unintended public access
Tools and Resources
Static Site Generators
These tools automate the creation of static HTML files from templates and content:
- Hugo – Fastest static site generator, written in Go
- Jekyll – Ruby-based, popular for GitHub Pages
- Gatsby – React-based, excellent for content-heavy sites
- Next.js – React framework with static export capability
- Eleventy (11ty) – Simple, JavaScript-based, zero-config
Most support build commands like npm run build that output a dist/ or _site/ folder—perfect for S3 deployment.
Deployment Tools
Automate uploads and reduce manual effort:
- aws-s3-static-website – Node.js CLI tool that uploads, sets headers, and configures S3 in one command
- Netlify CLI – Even though Netlify is a competitor, its deploy tool can push to S3 via plugins
- GitHub Actions – Free CI/CD workflows that auto-deploy on git push
Example GitHub Actions workflow (.github/workflows/deploy.yml):
name: Deploy to S3
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Build site
run: npm run build
- name: Deploy to S3
uses: jakejarvis/s3-sync-action@master
with:
args: --delete --acl public-read
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
SOURCE_DIR: dist/
Validation and Testing Tools
- Google PageSpeed Insights – Analyzes performance and suggests optimizations
- Web.dev – Lighthouse-based audit tool from Google
- GTmetrix – Detailed waterfall charts and load analysis
- SSL Labs (SSL Test) – Validates HTTPS configuration
- Redirect Checker – Ensures no redirect loops
Learning Resources
- AWS S3 Static Website Hosting Documentation
- Amazon CloudFront Overview
- Netlify Guide to S3 Hosting
- YouTube: Deploy React App to S3 (Step-by-Step)
Real Examples
Example 1: Personal Portfolio with React and S3
A developer builds a React portfolio using Create React App. After running npm run build, the build/ folder contains all static assets. Using the AWS CLI, they sync the folder to an S3 bucket named portfolio.johndoe.dev.
They enable static website hosting with index.html as both index and error document. Then, they create a CloudFront distribution with an ACM certificate for portfolio.johndoe.dev, and update DNS via Cloudflare. The site loads in under 1.2 seconds globally, with a 98/100 Lighthouse score.
Example 2: Documentation Site with Hugo
A software company uses Hugo to generate API documentation from Markdown files. Their CI pipeline runs daily: pull code → build Hugo → upload to S3 → invalidate CloudFront cache.
They use a custom bucket policy that restricts access to their company’s IP range for staging, but opens it publicly for production. They also set Cache-Control headers to cache assets for 1 year and HTML for 1 hour, ensuring users always see the latest docs without unnecessary reloads.
Example 3: Marketing Landing Page with HTML/CSS/JS
A startup creates a one-page marketing site using vanilla HTML, CSS, and JavaScript. They use Netlify’s static site generator to preview locally, then export the final build. Using the AWS S3 console, they upload the files and enable website hosting.
They add a CloudFront distribution with HTTPS and set up a custom domain. They monitor traffic via CloudWatch and notice a 60% reduction in load times compared to their previous shared hosting provider.
Example 4: Open-Source Project Documentation
An open-source project hosts its documentation on S3. Contributors submit PRs to the GitHub repo. Each merge triggers a GitHub Action that builds the docs using Docusaurus and deploys them to S3. The site is available at docs.projectname.org with full HTTPS and global CDN delivery.
They use versioned folders (/v1/, /v2/) to maintain historical documentation and use S3 lifecycle rules to archive older versions after 2 years.
FAQs
Can I host a dynamic website on S3?
No. S3 is designed for static content only. You cannot run server-side code like PHP, Node.js, or Python on S3. For dynamic functionality (forms, user authentication, databases), you need to pair S3 with AWS Lambda, API Gateway, or a third-party backend service like Firebase or Supabase.
Is hosting on S3 free?
Yes, within AWS Free Tier limits: 5 GB of storage, 20,000 GET requests, and 2,000 PUT requests per month. Most small static sites stay well under these limits. Beyond that, pricing is extremely low—$0.023 per GB stored and $0.0004 per 1,000 requests.
Why is my site loading slowly on S3?
Without CloudFront, your site is served from a single AWS region. Users far from that region experience higher latency. Enable CloudFront to cache content globally. Also, check if files are compressed and if cache headers are set correctly.
How do I fix a 403 Forbidden error?
This usually means your bucket policy doesn’t allow public read access. Double-check that:
- “Block all public access” is disabled
- Your bucket policy includes a statement allowing
s3:GetObjectfor* - File permissions (ACLs) are set to public-read (automatically handled by CLI sync)
Can I use S3 with a custom domain without CloudFront?
Yes, but only for subdomains (e.g., www.yourdomain.com) using a CNAME record. Apex domains (e.g., yourdomain.com) require CloudFront or a redirect bucket because S3 doesn’t support A records directly.
Do I need to worry about SEO with S3-hosted sites?
No. S3-hosted static sites are fully SEO-friendly. Search engines crawl HTML content just like any other website. Ensure you use proper meta tags, semantic HTML, structured data, and a sitemap.xml file. CloudFront and HTTPS further improve SEO by enhancing site speed and security signals.
What happens if my S3 bucket is deleted?
If versioning is enabled, you can restore previous versions. If not, files are permanently lost. Always enable versioning and consider backing up critical sites to a second bucket or local storage. Use tools like aws s3 sync to create regular backups.
Can I host multiple static sites on one S3 bucket?
Technically yes, by using folders (e.g., /site1/, /site2/), but each site needs its own bucket to be accessible via a unique domain or subdomain. S3 website hosting is bucket-specific. To host multiple domains, create separate buckets and configure CloudFront distributions or use subpaths with a reverse proxy (not recommended).
How do I update my site after deployment?
Rebuild your static site locally or via CI/CD, then re-upload using aws s3 sync or the S3 console. CloudFront caches content, so after uploading, invalidate the cache via CloudFront → Distributions → Invalidations → Create Invalidation → Enter /* → Submit.
Conclusion
Hosting a static site on Amazon S3 is a powerful, scalable, and economical solution for modern web development. With its seamless integration with CloudFront, automatic scaling, and enterprise-grade reliability, S3 eliminates the operational overhead of traditional hosting while delivering exceptional performance worldwide.
This guide walked you through every critical step—from creating your first bucket and uploading files to enabling HTTPS, optimizing caching, securing access, and deploying with automation. You’ve also seen real-world examples and learned how to avoid common pitfalls.
Whether you’re a solo developer, a startup, or a large organization, S3 provides the foundation for fast, secure, and cost-efficient static websites. Combined with modern static site generators and CI/CD pipelines, it empowers you to focus on building great content—not managing servers.
Now that you know how to host a static site on S3, take your next project live. Start small, iterate fast, and leverage AWS’s global infrastructure to reach users anywhere, anytime.