I over-engineered a personal website and I regret nothing
Most people build a personal website in a weekend using Squarespace or Wix.
I used Terraform.
The requirements
Like any good engineer, I started by writing requirements for a website that would hold maybe three blog posts and a resume PDF:
- Must be fast
- Must cost $0/month
- Must be "production grade" (this one is my fault)
- Must have infrastructure-as-code because apparently I have something to prove
Normal people: git push → GitHub Pages → done.
Me: opens a new Terraform file
The architecture
Here's the full system design. Yes, I drew this out. Yes, it's for a personal blog.
[ Browser ]
|
v
[ Cloudflare CDN ] <-- ~300 edge locations globally
| because my 3 readers deserve low latency
v
[ Cloudflare Pages ] <-- static site, auto-deploys on git push
|
v
[ Docusaurus build ] <-- React + Markdown = blog + docs site
|
[ Cloudflare R2 ] <-- resume PDF, because S3 costs money
|
[ Terraform ] <-- manages all of the above
|
[ GitHub Actions ] <-- runs npm audit weekly (security theater, but mine)
Total monthly cost: $0.
The domain (bevani.dev) costs ~$10/year. That's it. Everything else is free tier.
Why Cloudflare Pages over GitHub Pages?
Honestly? I wanted a CDN and GitHub Pages uses Fastly which has fewer edge locations. The real reason is that I wanted to learn Cloudflare's stack and this was a good excuse.
But the performance argument is real — if someone in Singapore opens my resume link, Cloudflare serves it from an edge node nearby instead of a US datacenter. Whether anyone in Singapore will ever read my blog is a separate question.
The $0 stack breakdown
| Layer | Tool | Why | Monthly cost |
|---|---|---|---|
| Framework | Docusaurus 3 | Markdown-first, looks good out of the box | $0 |
| Hosting | Cloudflare Pages | Free tier, global CDN included | $0 |
| CDN | Cloudflare | Comes with Pages, proxied = true | $0 |
| Resume storage | Cloudflare R2 | 10GB free, S3-compatible | $0 |
| Infra mgmt | Terraform | Because clicking in dashboards is temporary | $0 |
| CI/CD | GitHub Actions | npm audit on a cron schedule | $0 |
| TF state | Cloudflare R2 | Also free. Also R2. Yes I'm that guy | $0 |
| Domain | bevani.dev | The only real cost | ~$0.83/mo |
Grand total: 83 cents a month.
Things that went wrong (a partial list)
1. Webpack and webpackbar had a domestic dispute
Docusaurus ships with webpackbar for build progress. webpackbar needs webpack.
But webpack 5.97+ changed its options schema and webpackbar passed invalid options.
The fix: pin webpack to 5.96.1 and override all nested instances. Problem solved.
Time spent: longer than I'd like to admit.
2. Terraform's R2 backend needs 6 "skip" flags
Cloudflare R2 is S3-compatible but not exactly S3. When you use it as a Terraform backend, you have to tell Terraform to skip every AWS-specific validation:
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
skip_requesting_account_id = true
use_path_style = true
Five skip flags and one rename. That's how you know you're in compatibility layer territory.
3. My .npmrc was poisoning the lockfile
My global ~/.npmrc had legacy-peer-deps=true set from some project years ago.
npm on my Mac: uses relaxed peer dep resolution, generates lockfile
npm on Cloudflare: strict mode, tries to install from lockfile, explodes
The fix was a one-line .npmrc in the project. The real fix was asking why I had
that global setting in the first place. I did not investigate further.
4. Cloudflare Pages GitHub App wasn't installed
Terraform kept getting a 401 with error code 8000011 — "internal issue with your
Cloudflare Pages Git installation." The fix was going to the Cloudflare dashboard,
clicking through the project creation wizard just enough to install the GitHub App,
then backing out and letting Terraform do the actual work.
Clicking to authorize an OAuth app so that your IaC tool can do things: very normal.
Was this overkill?
Obviously.
But the infrastructure is reproducible from scratch with three commands:
make install
make tf-init
make deploy
And every content change is just a Markdown file edit + git push. Cloudflare handles
the build and deploy automatically. The whole thing costs less than a coffee per month.
Would I do it again? Yes. Will I blog consistently now that I have this? Ask me in a year.
-- Bala
