Hosting a static site on S3 with CloudFront
S3 can serve a website directly, but the website endpoint is HTTP only. For anything public, put CloudFront in front and keep the bucket private.
The shape of it
- A private S3 bucket holds the built files. Block Public Access stays on.
- A CloudFront distribution uses the bucket as its origin through Origin Access Control (OAC), so only CloudFront can read the objects.
- ACM issues a certificate (it must be requested in
us-east-1for CloudFront) for your custom domain. - Route 53, or your DNS provider, points the domain at the distribution.
Caching that doesn’t bite you
Build tools fingerprint asset filenames, so those files can be cached for a year:
aws s3 sync dist/_astro "s3://my-bucket/_astro" \
--cache-control "public,max-age=31536000,immutable"
Keep HTML revalidating so a deploy shows up straight away:
aws s3 cp dist/index.html "s3://my-bucket/index.html" \
--cache-control "no-cache"
If you serve HTML from a CDN cache anyway, invalidate just the HTML paths after a deploy rather than /*.
Security headers
CloudFront response header policies can add Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy and a Content-Security-Policy without any server code. For a static site with no third-party scripts, a tight CSP is easy to get right.
Directory URLs
CloudFront only maps / to index.html by default, not /blog/ to /blog/index.html. Either attach a tiny CloudFront Function that appends index.html to directory-style URLs, or use the S3 website endpoint as the origin.