Portfolio Architecture Case Study

Static portfolio hosted on AWS with an Astro build, private S3 origin, CloudFront distribution, Origin Access Control, ACM TLS, Terraform, and manually managed Cloudflare DNS.

The first phase focused on replacing ad hoc static hosting with a reproducible AWS deployment path. The site previously ran on a resilient homelab Kubernetes cluster with over 90 days of uptime, UPS-backed power, and redundant internal paths, but the public edge was still limited by the ISP router and uplink. That dependency was the bottleneck I could not realistically bypass from home.

For a DevOps-focused portfolio, that made the hosting story part of the signal, so the move to AWS gives the site a more reliable public edge. At the moment it also runs at near-zero cost because the architecture uses static hosting, CDN caching, and managed AWS services efficiently.

This site is also intended to grow as I practice and learn more AWS services, so each phase can showcase more of the surrounding cloud architecture. The hosting stack now models production concerns: private origin access, TLS, CDN caching, infrastructure as code, and a repeatable deploy script.

Frontend

Astro static build with real HTML output for fast loading and SEO.

Origin

Private S3 bucket with public access blocked and server-side encryption.

CDN

CloudFront with OAC, HTTPS redirect, ACM certificate, and managed caching.

DNS

Cloudflare records configured manually. The domain also supports mail and homelab Kubernetes apps, so DNS remains centralized outside AWS instead of moving to Route 53.

Deploy

Scripted build, S3 sync, cache headers, and CloudFront invalidation.

Astro instead of a client-only React SPA

The site is mostly static content, so Astro keeps the output SEO-friendly by generating real HTML instead of an empty JavaScript-rendered root.

Private S3 origin

The bucket is not public. CloudFront is the only intended read path, which keeps access control centralized at the CDN layer.

CloudFront Origin Access Control

OAC signs origin requests with SigV4 and replaces older public-bucket or Origin Access Identity patterns.

AWS-only Terraform, manual Cloudflare DNS

Terraform manages the AWS side while DNS records stay in Cloudflare. The domain is already used for mail and homelab Kubernetes apps, and Cloudflare is free for this use case, so Route 53 would add cost and another DNS control plane without clear benefit.

Short HTML cache, long asset cache

The entry document uses a short TTL so updates appear quickly. Non-HTML build assets can be cached for much longer because their filenames are generated by the build.

  1. Build the Astro site into `dist/`.
  2. Sync non-HTML build assets to S3 with long immutable caching.
  3. Upload `index.html` with a short cache TTL.
  4. Create a CloudFront invalidation for the entry document.
  5. Serve the site through CloudFront using the custom domain.