Core Implementation
Creating the Website Content
Create two minimal HTML files locally. These represent your deployable artifacts. In a real pipeline, these would be the output of your build step.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Static Site</title>
</head>
<body>
<h1>Site is live.</h1>
<p>Served from Amazon S3.</p>
</body>
</html>error.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Not Found</title>
</head>
<body>
<h1>404 - Page Not Found</h1>
<p>The resource you requested does not exist.</p>
</body>
</html>Upload both files to your bucket via the console or CLI. If using the CLI:
aws s3 cp index.html s3://your-bucket-name/index.html
aws s3 cp error.html s3://your-bucket-name/error.htmlAfter upload, verify both objects appear in the bucket with correct keys. Do not modify object permissions individually — access will be granted at the bucket policy level.
Applying the Bucket Policy
Navigate to “Permissions” > “Bucket policy”. Apply the following policy, replacing your-bucket-name with your actual bucket name:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}This policy grants any unauthenticated caller the ability to perform s3:GetObject on any object within the bucket. The /* suffix is intentional — it applies to all objects, not the bucket itself. Do not grant s3:ListBucket here; listing enables enumeration of all your object keys, which is unnecessary for a web host and a security exposure.
After saving, the bucket permissions tab will display a warning: “Publicly accessible”. This is expected and correct for this use case.
Validation
Navigate to the S3 website endpoint URL noted in the previous section. You should see your index.html rendered in the browser. Now navigate to a non-existent path, such as http://your-endpoint/nonexistent-page. You should see your error.html content — not the default AWS XML error response.
If you see an XML response like <Code>NoSuchKey</Code>, your error document is not configured correctly or the file was not uploaded with the exact key error.html.
If you see 403 Forbidden, the bucket policy has not been applied or Block Public Access is still preventing it. Verify the block settings and policy syntax.

In this section, I confirmed:
0 of 5 completed