Conceptual Foundations
How S3 Static Hosting Works
S3 is an object store, not a web server. When you enable static website hosting on a bucket, AWS activates an HTTP endpoint that maps GET requests to object keys. A request to /about/index.html maps to the object key about/index.html. S3 never executes code — it reads bytes and returns them with the appropriate content type derived from the object metadata.
This distinction matters architecturally: you cannot run server-side redirects, set dynamic response headers, or process form submissions through S3 alone. For SPAs using client-side routing (e.g., React Router, Vue Router), all routes must resolve to index.html — the error document field is commonly used for this, redirecting 404s to index.html so the client-side router takes over.
Bucket Policies vs. ACLs
AWS provides two mechanisms for controlling access to S3 objects: bucket policies and Access Control Lists (ACLs). Understanding the difference is not optional — misconfiguring this layer is the most common source of either broken sites or unintended public exposure.
ACLs are legacy object-level permissions. They operate per object and are coarse-grained. AWS has been progressively deprecating public ACL usage and, as of April 2023, new buckets block public ACLs by default. Relying on ACLs to make objects public is the wrong pattern.
Bucket policies are resource-based IAM policies attached to the bucket itself. They are expressive, auditable, and the correct tool for granting public read access to all objects in a hosting bucket. A policy that grants s3:GetObject to principal * on arn:aws:s3:::your-bucket/* is explicit, reviewable in your IaC, and easy to reason about.
The key architectural insight: use bucket policies for access control, not ACLs, unless you have a specific per-object access requirement.
The Block Public Access Setting
AWS introduced account-level and bucket-level “Block Public Access” settings to prevent accidental data exposure. For static website hosting, you must disable the block on public bucket policies specifically. This is an intentional gate — it forces you to make a deliberate decision to allow public access. You are not removing security; you are consciously opting in to a public read configuration, which is correct for this use case.
Conceptual Foundations Check
Question 1 of 2
You are deploying a React SPA with client-side routing to S3. Users get a 403 when navigating directly to /dashboard. What is the most likely cause?