← All posts

Setting Up This Website

Engineering: Web Apps

For a while, my personal site at raharoho.me has been sitting on InfinityFree — a free hosting provider that, while generous, comes with a few annoyances. The biggest one: SSL certificates need manual renewal every three months. Miss the reminder and your site goes down with a certificate error. The other irritation is a JavaScript-based cookie challenge injected on every request, which means web crawlers, link previewers, and automated tools often just see a blank page.

Both of those got old quickly. So this week I finally migrated. Here’s what the setup looks like now.

The monorepo

The site is a single public GitHub repo with two Astro projects:

/
├── landing/   → raharoho.me
└── blog/      → blog.raharoho.me (you are here)

Landing page — a simple personal card. Profile photo, name, title, links. The build output is one index.html. Nothing clever, which is the point.

Blog — what you’re reading now. Astro with Content Collections for Markdown posts. Posts live as .md files in src/content/posts/, and the frontmatter schema is validated by Zod at build time. No more silently broken dates.

Both are deployed to Cloudflare Pages on the free tier: global CDN, unlimited bandwidth, 500 builds per month.

CI/CD

Every pull request gets a preview deployment. The cloudflare/pages-action action posts the URL as a comment on the PR automatically — no extra scripting needed. On merge to main, both sites go to production.

- uses: cloudflare/pages-action@v1
  with:
    projectName: raharoho-blog
    directory: blog/dist
    gitHubToken: ${{ secrets.GITHUB_TOKEN }}  # posts preview URL on the PR

The preview workflow only triggers when files under landing/ or blog/ actually change, so PRs touching only workflows or docs don’t burn build minutes.

DNS and Terraform

My DNS has been managed via Terraform in a private repo for a while. The migration involved swapping the old InfinityFree A records for CNAME records pointing at Cloudflare Pages’ default domains. Cloudflare’s CNAME flattening handles the root domain correctly so no special tricks were needed there.

One thing I ran into: creating a Cloudflare Redirect Rule via Terraform requires the Zone > Transform Rules > Edit permission on the API token. The error message just says “request is not authorized”, which is not immediately obvious.

Why Astro

I wanted something that produces plain static HTML, handles Markdown well, and doesn’t require me to maintain a runtime. Astro fits. Content Collections in particular are nice — you get a typed schema for frontmatter, and build errors on violations instead of silent runtime surprises.

What this blog is for

I set up four categories to give myself some structure:

  • Engineering: Web Apps — web development, systems, things I’m building
  • Engineering: Networking — infrastructure, the lower layers
  • Traveling — I’m working through Indonesia
  • Automotive — I ride a Vespa and I’ve been eyeing ADV bikes

Not everything here will be technical. That felt important to decide up front.