A static site can be publicly available through CloudFront while its S3 origin remains private. This gives visitors an HTTPS endpoint without making the underlying S3 objects anonymously readable.
In this tutorial, I use Buckets by Serverless Creed to review and deploy a small static site, verify its access boundary in AWS, and inspect an incremental update. The update changes one file, adds another and leaves two files unchanged.
The walkthrough draws on my Windows deployment tests and a supplementary run on 8 October 2026. Historical examples are labelled with their original application versions and fixtures.
Understand the delivery setup
Visitors access the site through CloudFront over HTTPS. CloudFront requests the files from an S3 REST origin using an Origin Access Control (OAC). The bucket policy grants object-read access to the intended CloudFront distribution.
This setup makes the site available through CloudFront while restricting anonymous access to the underlying S3 objects.
An S3 REST origin differs from an S3 static website endpoint. This walkthrough uses the REST origin because OAC does not apply to S3 website endpoints. See AWS’s guidance on restricting access to an S3 origin.
Prepare the environment and test files
Install Buckets from the official download page. Before deploying, confirm your approval for the AWS resources, public site delivery and associated costs. Check the active AWS account, profile, budget alerts and cleanup plan.
My supplementary run on 8 October 2026 used Buckets by Serverless Creed v2.7.49 on Windows, with the aws-admin profile in the us-east-1 AWS region.
Earlier supporting tests used v2.7.17 for the initial deployment (TC-SITE-001) and v2.7.20 for incremental deployment (TC-SITE-002), using the default AWS profile.
Create a local folder named site containing these three files:
| File | Purpose |
|---|---|
index.html |
The page we will modify during the update |
style.css |
A stylesheet we will leave unchanged |
large-test.bin |
A binary file we will also leave unchanged |
Save index.html as UTF-8:
`html
<!doctype html>
<meta charset="utf-8">
<title>Aditi sandbox site</title>
<link rel="stylesheet" href="style.css">
<h1>Deployment revision 1</h1>
`
Save style.css as UTF-8:
body { font: 18px sans-serif; margin: 3rem; }
Create a 1 MiB binary test file by running this Python code from inside the site folder:
from pathlib import Path
Path("large-test.bin").write_bytes(b"x" * 1048576)
The binary file provides an unchanged object to track during the incremental update.
Before editing any files, record their names, sizes and SHA-256 hashes. Open PowerShell inside the site folder and run:
Get-ChildItem -File |
Select-Object Name, Length, @{
Name = 'SHA256'
Expression = {
(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash
}
} |
Export-Csv ..\manifest-before.csv -NoTypeInformation
This saves manifest-before.csv in the parent directory. Keep manifests and screenshots outside the site folder so they are not uploaded as website content.
Review and Deploy the Site
In Buckets, open Build → Publish → Folder → Live Site
and select the local site folder.
Choose the disposable destination bucket and verify the AWS profile and region. For the initial deployment, use a new CloudFront distribution. Leave Delete remote-only objects unchecked.
Select Preview diff. My initial preview showed:
- 3 uploads: index.html, style.css and large-test.bin
- 0 unchanged files
- 0 remote-only files

Initial deployment preview: three uploads, no unchanged files and no remote-only objects.
Select Confirm deploy, then review the affected resources, required permissions and estimated costs in the Cost & permission review before submitting.
The deployment connects the S3 bucket to an OAC-backed CloudFront distribution. Buckets reported Deployment submitted and three paths invalidated.

Buckets reported deployment submission and three invalidated paths.
Verify delivery and the private S3 origin
Open the CloudFront HTTPS URL in an Incognito or signed-out browser. In my supplementary run, the page displayed Deployment revision 1.

CloudFront served Deployment revision 1 in Incognito.
Next, copy the S3 Object URL for index.html from AWS Console and open it in Incognito. Use the plain object URL, without presigned credentials. My direct S3 request returned AccessDenied.

An unsigned request for the S3 index object returned AccessDenied.
Verify the configuration independently in AWS Console:
- Under CloudFront → Distribution → Origins, confirm that the S3 origin has the intended OAC attached.
- Under S3 → Bucket → Permissions → Bucket policy, inspect the CloudFront access permission.
In my test, the bucket policy allowed s3:GetObject to the cloudfront.amazonaws.com service principal, with an AWS:SourceArn condition matching the intended distribution.
The CloudFront S3 origin had an OAC attached.
The bucket policy scoped CloudFront object-read access to the intended distribution. These results demonstrate the intended access boundary: the page was available through CloudFront, while the unsigned direct S3 request was denied. Check the stylesheet separately through the CloudFront URL at /style.css.

The incremental preview identified two uploads and two unchanged files.
Review the changes and submit the deployment. In AWS Console, open the distribution’s Invalidations tab. My completed invalidation contained exactly these paths:
/index.html
/notes.txt

The completed invalidation targeted only /index.html and /notes.txt.
Verify the Updated Site and Deployment Scope
After the incremental deployment, I verified that the CloudFront invalidation reached Completed status and included exactly two paths: /index.html and /notes.txt.
The Buckets preview identified 2 uploads and 2 unchanged files, matching the intended changes:
-
Modified:
index.html -
Newly added:
notes.txt -
Unchanged:
style.cssandlarge-test.bin
This confirmed that Buckets correctly identified the files requiring an update while recognizing the unchanged files.
As a final verification step, the updated index.html and newly added notes.txt can be accessed through the CloudFront HTTPS endpoint. For deeper verification, S3 object metadata such as Last modified timestamps or version IDs can also be compared before and after deployment.
Verify OAC list, create and delete operations
Alongside the site deployment, I tested OAC management using a separate, disposable OAC that was not attached to a distribution.
In Buckets, open the Origin Access Control list under the authorized AWS profile. Record the existing entries so they can be preserved.
Create a test OAC with these settings:
| Setting | Value |
|---|---|
| Name | buckets-intern-aditi-oac-20261007 |
| Origin type | S3 |
| Signing behavior | Always |
| Signing protocol | SigV4 |
After creation, I verified that the new OAC appeared in both Buckets and AWS Console.

Buckets created the disposable OAC using S3, Always signing and SigV4.

The new OAC also appeared in AWS Console.
I then deleted only the disposable, unattached OAC. Buckets displayed a successful deletion result, and an independent AWS Console check confirmed that the entry was absent. The pre-existing OAC remained in the list.

Buckets reported successful deletion of the unattached test OAC.

The refreshed AWS list no longer contained the test OAC; the existing entry remained.
The deletion dialog also explained that AWS blocks deletion while an OAC is in use. This test demonstrated deletion of an unattached OAC; the OAC serving the deployed site was retained.
Troubleshooting: OAC Creation Error
During one deployment attempt, the site files uploaded, but OAC creation returned “The parameter Name is too big.” I checked AWS to identify the resources already created before retrying with a shorter disposable bucket name. The retry successfully created the delivery stack. The exact generated-name cause was not confirmed.

OAC creation failed with a name-length error after the site files uploaded
Cleanup and Resource Teardown
After completing the initial deployment, private-origin verification, and incremental update tests, I removed the disposable AWS resources created for this walkthrough.
I followed the dependency-aware cleanup order to avoid deleting resources that were still in use.
1. Remove the CloudFront distribution
I disabled and deleted the test CloudFront distribution. After deletion, the AWS CloudFront console displayed Distributions (0), confirming that no distributions remained in the selected account.

AWS CloudFront console showing zero distributions after deleting the test distribution.
2. Delete the Origin Access Control (OAC)
Using the Origin Access Controls interface in Buckets, I deleted the OAC associated with the test deployment.
Buckets displayed a successful deletion message. I independently checked the AWS CloudFront console, which showed Origin access controls (0).

Buckets confirming successful deletion of the test Origin Access Control.
3. Empty the S3 bucket
Before deleting the bucket, I used Buckets to remove the four test objects. The application confirmed that the bucket was emptied and the bucket list was synchronized.
4. Delete the S3 bucket
Finally, I deleted the disposable S3 bucket using Buckets. The application displayed a successful deletion notification and synchronized the bucket list.

Buckets confirming deletion of the disposable S3 bucket and synchronization of the bucket list.
Cleanup Result
The CloudFront distribution and OAC were confirmed absent in AWS, while Buckets confirmed the deletion of the four S3 objects and the test bucket.
This completed the application-side cleanup of the disposable resources used for the tutorial.
Conclusion
In this walkthrough, we deployed a static website using Buckets by Serverless Creed, with Amazon S3 as a private origin and Amazon CloudFront providing HTTPS delivery.
We verified that:
- The website was accessible through its CloudFront HTTPS URL while direct, unauthenticated S3 access was denied.
- CloudFront Origin Access Control (OAC) was configured to support access to the private S3 origin.
- The incremental deployment preview identified the changed and newly added files for upload while marking unchanged files separately.
- CloudFront invalidation targeted the updated paths, allowing the latest website content to be served.
- The disposable CloudFront distribution, OAC, and S3 resources were removed after testing.
The key takeaway is that deploying a website is only part of the process. Verifying origin access, reviewing incremental changes, checking cache invalidation, and cleaning up test resources are equally important.
By combining the Buckets deployment workflow with independent AWS Console checks, we can better understand what the application performs and what AWS actually enforces.
Top comments (0)