Here’s the clean setup for hosting one static HTML page on AWS, like an ID page / entity page.
Option A — fastest: public S3 static website
Use this when you just need a public HTML page live quickly.
1. Create the bucket
Go to AWS Console → S3 → Create bucket.
Use a simple bucket name, for example:
colony-insulation-id-page
If this will use a custom domain later, the bucket name often needs to match the domain/subdomain, like:
id.getcolonyinsulation.com
Leave most defaults alone for now.
2. Upload your HTML file
Inside the bucket, upload:
index.html
Make sure it is exactly lowercase:
index.html
Not Index.html, index.htm, or index.html.html.
3. Enable static website hosting
Go to:
S3 bucket → Properties → Static website hosting
Choose:
Enable
Host a static website
Index document: index.html
Save it.
AWS’s static site setup specifically requires enabling static website hosting and configuring the index document before testing the website endpoint. (AWS Documentation)
4. Make the bucket public
Go to:
S3 bucket → Permissions → Block public access
Click Edit.
Uncheck:
Block all public access
Save.
AWS notes that public S3 websites require disabling relevant Block Public Access settings and adding a bucket policy granting public read access. (AWS Documentation)
5. Add a bucket policy
Still under:
Permissions → Bucket policy
Paste this, replacing the bucket name:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForStaticWebsite",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::colony-insulation-id-page/*"
}
]
}
Replace:
colony-insulation-id-page
with your real bucket name.
Save it.
6. Use the website endpoint, not the raw S3 URL
Go back to:
Properties → Static website hosting
Copy the Bucket website endpoint.
It will look like:
http://colony-insulation-id-page.s3-website-us-east-1.amazonaws.com
That is the URL you use.
Do not use the regular S3 object URL like:
https://colony-insulation-id-page.s3.amazonaws.com/index.html
That is the common cause of the XML AccessDenied page.
Option B — better/professional: S3 + CloudFront
Use this if you want HTTPS, cleaner delivery, and a better long-term setup.
Basic flow
- Create the S3 bucket.
- Upload
index.html. - Keep the bucket private.
- Create a CloudFront distribution.
- Set the S3 bucket as the origin.
- Use Origin Access Control so CloudFront can read the private bucket.
- Set:
Default root object: index.html
CloudFront uses the default root object when someone visits the distribution root instead of requesting a file directly. (AWS Documentation)
CloudFront URL will look like:
https://d123abc456.cloudfront.net
If you use CloudFront, you do not necessarily need S3 static website hosting enabled. CloudFront can serve the object directly from S3, but you must set the default root object and bucket access correctly.
For your current AccessDenied error
Most likely, one of these is wrong:
You are using the raw S3 URL instead of the website endpoint.
index.html is not public.
Static website hosting is not enabled.
The bucket policy does not grant s3:GetObject.
CloudFront has no default root object.
CloudFront does not have permission to read the bucket.
My recommended setup for your use case
For these simple generated entity/ID pages, I’d do:
S3 public static website first
Then later, if you want HTTPS/custom domain polish:
CloudFront + custom domain + SSL certificate
For right now, get the page working at the S3 website endpoint first. Then layer CloudFront/custom domain only after the base page loads.