CloudFront Website Hosting with a Private Amazon S3 Bucket
AWS Architecture Guide — CloudFront + Private S3 (OAC)
Table of Contents
- Objective
- Amazon S3 Bucket Configuration
- Create the CloudFront Distribution
- Configure Origin Access Control (OAC)
- Update the S3 Bucket Policy
- Configure the Default Root Object
- Configure Custom Error Responses
- Summary
1. Objective
This document describes the process of hosting a static website on Amazon S3 and making it publicly accessible through Amazon CloudFront, while keeping the underlying S3 bucket fully private.
S3 Block Public Access remains enabled at all times. CloudFront retrieves objects from the private bucket using Origin Access Control (OAC), ensuring that the S3 bucket cannot be accessed directly and all traffic is served through the CloudFront distribution.
Key Principle The S3 bucket is never made public. CloudFront acts as the sole authorized reader of the bucket contents via a signed, service-level trust relationship (OAC).
2. Amazon S3 Bucket Configuration
2.1 Create the S3 Bucket
- Sign in to the AWS Management Console and navigate to S3 → Create bucket.
- Enter a globally unique bucket name (e.g.,
my-private-website). - Select the required AWS Region for the bucket.
2.2 Keep Public Access Blocked
While creating the bucket, retain the default security setting:
- Block all public access → Enabled
⚠️ Important Do not disable Block Public Access. The bucket must remain private at all times; public access is provided exclusively through the CloudFront distribution.
3. Create the CloudFront Distribution
Navigate to CloudFront → Distributions → Create distribution.
3.1 Origin Configuration
Under Origin, select the S3 bucket created in the previous step. Ensure the S3 bucket origin is used — not the S3 static website hosting endpoint.
Example Origin Domain:
my-private-website.s3.ap-south-1.amazonaws.com
4. Configure Origin Access Control (OAC)
Under Origin access, select the following option:
- Origin access control settings (recommended)
If an Origin Access Control does not already exist:
- Select Create new OAC.
- Configure it for the S3 origin using the recommended signing behavior.
OAC enables CloudFront to securely and directly access objects stored in the private S3 bucket, using SigV4 signed requests, without requiring the bucket to be publicly accessible.
5. Update the S3 Bucket Policy
After the Origin Access Control is configured, CloudFront automatically generates a bucket policy required to grant it read access. Copy this policy and apply it under:
S3 → Your Bucket → Permissions → Bucket policy
⚠️ Do Not Modify Generated Values Use the policy exactly as generated by CloudFront. Do not manually edit the bucket name, account ID, or distribution ID placeholders once CloudFront has populated them.
Reference policy structure:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR-ACCOUNTID:distribution/YOUR-DISTRIBUTION-ID"
}
}
}
]
}
This policy grants the CloudFront service principal permission to read (GetObject) objects from the S3 bucket, scoped specifically to the originating CloudFront distribution via the AWS:SourceArn condition — without exposing the bucket to the public.
6. Configure the Default Root Object
Navigate to the distribution's General settings tab and configure:
| Setting | Value |
|---|---|
| Default root object | index.html |
This ensures that requests made to the root of the distribution (e.g., https://<distribution-domain>/) are automatically served the index.html file.
7. Configure Custom Error Responses
Configure CloudFront custom error responses to handle 403 (Forbidden) and 404 (Not Found) errors gracefully. This is especially important for single-page applications (SPAs) and consistent error handling.
7.1 403 Error
| Setting | Value |
|---|---|
| HTTP Error Code | 403 |
| Response Page Path | /index.html |
7.2 404 Error
| Setting | Value |
|---|---|
| HTTP Error Code | 404 |
| Response Page Path | /index.html |
If custom error pages are used, upload them to the S3 bucket alongside the primary website files (e.g., index.html).
8. Summary
With this configuration, the static website is served publicly through the CloudFront distribution domain, while the source S3 bucket remains fully private and inaccessible via direct S3 URLs. Access control is enforced entirely through Origin Access Control and the CloudFront-generated bucket policy, aligning with AWS security best practices for static website hosting.
Result
| Aspect | Status |
|---|---|
| Public access | Enabled via CloudFront only |
| S3 Block Public Access | Enabled |
| Direct S3 bucket/object URLs | Inaccessible |