I wanted a small place on the internet that felt like mine.
Not a big portfolio with a dozen pages I would never update. Not a blog platform with more structure than writing. Just a simple site where I could put a few thoughts, share pictures from trips, and outline the work I have done without making the whole thing feel bloated.
The requirements for it were pretty clear from the beginning:
- It should be easy to maintain.
- It should be fast.
- It should support natural writing without needing code changes in the long run.
- It should handle images well.
- It should be easy to deploy.
- It should be cheap to operate.
Finding the best solution
When I approach any requirements, I often like to do a first-pass filtering step to remove any solutions that won’t meet the requirements. I find that this helps in reducing the eventual selection-set down to something reasonable and prevents going down paths that won’t work out in the end.
Quite immediately, solutions like Webflow, Framer, and Wix were off the table. While these solutions meet the maintainability and technical requirements, they aren’t cheap.
Vercel and Netlify were much more reasonable alternatives. Either one would have worked well for a personal site, and for many personal sites they are probably the easiest answer. But for this project, part of the point was owning the path from source code to infrastructure. I already work comfortably in AWS, and I liked the idea of the site being deployed through infrastructure I could describe, review, and recreate.
That narrowed the shape of the solution pretty naturally: a static site generator, content written in MDX, optimized images, and a small AWS deployment that I could keep cheap and boring. This led me to a stack that consisted of Astro, AWS, and Tailwind CSS.
Why Astro fit
Most of this site is static content. None of that needs a large client-side app just to render.
Astro is a good fit for this kind of site because it starts from static HTML and only adds client-side JavaScript where explicitly needed. I am not trying to turn this into an SEO machine, but it is also a great architecture for making pages easy to index.
It also provides room to grow. If I eventually want a small interactive component, I can reach for React in that one place without turning the entire site into a React app. Eventually, I’ll probably upload a couple demos using some of my favorite libraries like Media Bunny. This provides a nice split where I can outline the boring stuff in an easy, maintainable way while remaining flexible when I want to add additional functionality.
Within Astro, you can define content collections for structured writing, which gives MDX files typed frontmatter and a predictable shape. That is a nice middle ground for a personal site: the body of a post can stay as natural prose, while metadata like title, description, publish date, and tags can still be validated at build time.
For example, this post has frontmatter like:
---
title: "Building this site"
description: "How this site is built, deployed, and wired up behind the scenes with Astro, Tailwind, AWS, CDK, Route 53, GitHub Actions, and Microsoft 365."
publishedAt: "2026-06-21"
---
Why AWS
I used AWS because I am already comfortable there. For a static site, S3 and CloudFront are a very normal, boring choice in the best way. It also lets me keep the costs down. At this scale, the practical monthly cost should mostly be the $0.50 Route 53 public hosted zone. The rest should be tiny unless traffic or deploy volume changes in a meaningful way.
The shape is simple:
Astro build -> S3 -> CloudFront -> Route 53
Why CDK
I could have clicked all of this together in the AWS console, but I know I would forget some detail six months later. After working at Amazon, I really came to appreciate infrastructure-as-code. It’s one of those things that you don’t realize how important it is until you have tons of resources set up with no easy way to reconstruct how everything fits together.
Using AWS CDK means the infrastructure lives with the site. The bucket, distribution, DNS, certificate, deployment behavior, and cache headers are all described in code. If I come back later, I do not have to reconstruct the setup from memory.
When the CDK stack is deployed, the static build files are uploaded to S3. CloudFront then serves them over HTTPS and caches them close to users. The stack also provisions a Route 53 Public Hosted Zone for the domain. This allowed me to easily point the root of the domain to the CloudFront endpoint and additionally add the necessary DNS records for email and other stuff I have on it like Home Assistant. For the SSL certificate, AWS provides free ACM certificates if the endpoint is AWS-owned (e.g., CloudFront).
Deploying from GitHub
I wanted deploys to be boring too. Push to the repo, build the site, deploy the CDK stack.
The GitHub Actions workflow uses OpenID Connect to assume a role in AWS, which means I do not have long-lived AWS access keys sitting in GitHub.
The workflow installs dependencies, builds Astro, writes the local infrastructure environment file from GitHub variables, assumes the AWS role, and runs CDK deploy.
That gives me a pretty nice maintenance loop. I can change copy, update a photo, or tweak infrastructure and let the same deploy path handle it.
Owning my email
The email part was more personal than technical.
After my college email was deleted, I realized how much identity can get tied up in an address I do not actually control. I wanted an email address on my own domain, something I could keep using for the long-term.
I set up Microsoft 365 for mail and added the required DNS records in Route 53. I won’t go too much into detail here, but there’s some great reading on what these do outlined by CloudFlare.
MXfor mail deliveryTXTfor SPF_dmarcfor DMARC- DKIM selector
CNAMErecords autodiscoverfor Microsoft clients
The records are managed alongside the rest of the site infrastructure. It is a small thing, but it makes the domain feel more complete. The site and email are both parts of the same idea: a little corner of the internet that I own and can keep tending.
That is really the point of the whole setup. It is small enough to maintain, flexible enough to grow, and owned end to end.