I’ve been there—you upload an HTML file to S3, configure static website hosting, grab that endpoint URL, and all you see is a blank page and a 403 Forbidden error staring back at you. After troubleshooting for 30 minutes, I realized the issue wasn’t the HTML or my upload—it was a combination of permissions, public access settings, and bucket configuration that I missed. In this post, I’ll walk through exactly what causes this and how to fix it.
The Problem
When you visit your S3 static website endpoint (like http://my-bucket.s3-website-us-east-1.amazonaws.com), you get a 403 Forbidden error. No objects load, and even your index document doesn’t appear.
| Error Type | Description |
|---|---|
| 403 Forbidden | The server understood the request but refuses to authorize it. S3 requires explicit read permissions. |
| Access Denied | CloudFront or S3 doesn’t have permission to read the object. |
Why Does This Happen?
- S3 Block Public Access is enabled — At the account level, the account-wide setting for
BlockPublicPolicyprevents any public bucket policy from taking effect. At the bucket level,RestrictPublicBucketsblocks public access even if a policy exists. - No bucket policy granting GetObject to everyone — S3 is private by default. Without an explicit
s3:GetObjectallow for"Principal": "*", no one can read anything. - Static website hosting not configured — The bucket must have the static website hosting setting enabled, and you need to specify an index document (usually
index.html). - Objects uploaded with private ACL — If you uploaded objects with a private canned ACL, the bucket policy doesn’t override it. The object itself is locked down.
The Fix
Step 1: Disable Block Public Access
First, check and disable S3 Block Public Access settings at both the account and bucket level:
# Disable at bucket level
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration \
BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
Step 2: Add Bucket Policy for Public Read Access
Create a bucket policy that allows public s3:GetObject access:
# Save this as bucket-policy.json
cat > bucket-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
EOF
# Apply the policy
aws s3api put-bucket-policy \
--bucket my-bucket \
--policy file://bucket-policy.json
Step 3: Enable Static Website Hosting
Verify that static website hosting is enabled and the index document is set:
# Enable static website hosting
aws s3api put-bucket-website \
--bucket my-bucket \
--website-configuration file://website-config.json
Create website-config.json:
{
"IndexDocument": {
"Suffix": "index.html"
},
"ErrorDocument": {
"Key": "error.html"
}
}
Verify the configuration:
aws s3api get-bucket-website --bucket my-bucket
Step 4: Ensure Objects Have Public Read ACL
If objects were uploaded before the policy was applied, re-upload them or change their ACL:
# Copy an object and update ACL to public-read
aws s3 cp s3://my-bucket/index.html s3://my-bucket/index.html \
--acl public-read \
--metadata-directive COPY
How to Run This
- Replace
my-bucketwith your actual S3 bucket name - Ensure you have AWS CLI credentials configured with permissions to manage S3 bucket policies and settings
- Run the commands in order — disable Block Public Access first, then add the policy
- Upload your HTML files (or re-sync them) to the bucket
- Visit your static website endpoint and verify the 403 error is gone
Is This Safe?
Making your S3 bucket public for a static website is acceptable for public content—HTML, CSS, JavaScript, images. Never store sensitive data (credentials, API keys, private documents) in a public bucket. Use CloudFront in front of S3 for additional security and performance, and consider signed URLs for sensitive assets.
Key Takeaway
The 403 Forbidden error on an S3 static website is almost always caused by Block Public Access settings, a missing bucket policy, or objects without public read permissions. Check all three, and your website will be up and running.
Have questions or ran into a different S3 issue? Connect with me on LinkedIn or X.