All projects
Cloud

Static Site Delivery

This portfolio’s delivery layer rebuilt on S3 and CloudFront. The bucket stays private while the edge serves the site.

CloudFront and private S3 architecture from the hosting write-up
Architecture diagram

At a glance

  • Origin bucket has no public access
  • OAC over the deprecated OAI
  • HTTPS terminated at the edge
  • Static Next.js export, no server

S3 · CloudFront · OAC · IAM · Next.js

Architecture

CloudFront serves a private S3 bucket over HTTPS using Origin Access Control, with no public path to the originBrowserpublic internetCloudFrontTLS · Default Root ObjectS3 bucketBlock Public Access: onHTTPSOAC✕no public path to the originCloudFront is the only principal the bucket trusts.

Scroll the diagram horizontally to explore the full flow.

The problem

Managed hosting hides most of the delivery layer. I rebuilt this portfolio's static hosting path to understand what the platform was abstracting away.

The decision

The S3 bucket keeps Block Public Access enabled and has no public website endpoint. CloudFront is the only principal allowed to read objects, authenticated through Origin Access Control instead of the legacy Origin Access Identity model.

CloudFront terminates HTTPS at the edge while the private bucket remains an origin rather than a public website.

What broke

Every request returned 403, which initially looked like an IAM failure. The object permission was correct. CloudFront was requesting an empty key because its Default Root Object was unset.

S3 returned 403 rather than 404 for that missing key because the distribution could read objects but could not list the bucket. The response headers exposed the real failure faster than repeatedly rewriting the bucket policy.

Shape of the build

  • Static Next.js export
  • Private S3 origin
  • CloudFront global delivery
  • Origin Access Control
  • HTTPS at the edge
  • No public bucket policy
View Markdown on GitHubRead the write-up Repository Why I still ship on Vercel