← all articles

Hosting a static site on S3 with CloudFront

·1 min read

awss3cloudfront

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

  1. A private S3 bucket holds the built files. Block Public Access stays on.
  2. A CloudFront distribution uses the bucket as its origin through Origin Access Control (OAC), so only CloudFront can read the objects.
  3. ACM issues a certificate (it must be requested in us-east-1 for CloudFront) for your custom domain.
  4. 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.