Skip to content
Void Engineering
Go back

How this site runs for the price of the domain

I wanted to host a simple website on my domain without paying anything else out of pocket.

This post is the exact path I took, including the parts that failed. If you’ve got a domain sitting at a registrar doing nothing, you can copy this in an evening.

Table of contents

Open Table of contents

What you end up with

What you need before starting: a domain, a GitHub account and a free Cloudflare account. Node 22 on your machine helps if you want to preview locally, but you can get by without it.

Why static, and why Cloudflare

A blog doesn’t need a server. Every page can be built once into plain HTML and handed out as files, which is the cheapest thing a host can do. That’s why so many hosts give it away.

I went with Cloudflare over GitHub Pages or Netlify for two reasons. Requests for static files on Cloudflare are free with no cap, so if a post ever takes off I still don’t get a bill. And Cloudflare is also a DNS provider, so the domain, the certificate and the hosting all sit in one dashboard.

Step 1: Move your DNS to Cloudflare

My domain is registered at Squarespace. You don’t have to transfer the registration anywhere. You only point the domain’s nameservers at Cloudflare, and Cloudflare takes over answering DNS for it.

  1. In Cloudflare, click Add a domain, type your domain and pick the Free plan.
  2. Cloudflare scans your current DNS records and copies them over. Stop here and check the list before you continue.
  3. If you use email on the domain, check that the MX, SPF, DKIM and DMARC records made it over. If one’s missing, add it now or your mail stops working.
  4. At your registrar, turn DNSSEC off first. If it’s on when you swap nameservers, the domain can stop resolving completely.
  5. Still at the registrar, switch to custom nameservers and paste in the two Cloudflare gave you.

Then wait. Mine switched over in a few minutes, though it can take longer. The domain’s Overview page in Cloudflare says Active once it’s done.

Step 2: Make the site

Create an empty repo on GitHub.

Then scaffold AstroPaper locally:

npm create astro@latest -- --template satnaing/astro-paper
cd your-site
npm install
npm run dev

The site lives at localhost:4321 while you edit. The settings you’ll want to change first are in astro-paper.config.ts: your site URL, title, author, timezone and social links. Posts go in src/content/posts/ as Markdown files with a small block of frontmatter at the top.

Two things that would have saved me trouble later.

Pin your Node version

Add a .node-version file at the root with the version you build with. Cloudflare reads it and installs the same one.

Keep your lock file in sync

Cloudflare installs with npm ci, which fails if package-lock.json doesn’t match package.json. That’s what killed my first deploy. If you change dependencies, run npm install and commit both files.

Push it:

git init
git add .
git commit -m "Initial site"
git branch -M main
git remote add origin git@github.com:YOUR-USER/YOUR-REPO.git
git push -u origin main

Step 3: Deploy on Cloudflare

Go to Workers & Pages, then Create. Cloudflare will probably start you on a Worker rather than Pages. That’s what happened to me. In the end it didn’t matter, so if you’re following this guide verbatim, use a Worker.

Connect your GitHub account, pick the repo and set:

Before you deploy, add a wrangler.jsonc to the root of the repo. Without it, wrangler deploy spots the Astro project and adds Cloudflare’s server adapter on its own. My static site got turned into a server app and the deploy failed. This file tells it to upload the built files and nothing else:

// Deploys the built site as static files on Cloudflare (no server code).
{
  "name": "your-worker-name",
  "compatibility_date": "2026-10-01",
  "assets": {
    "directory": "./dist",
    "not_found_handling": "404-page"
  }
}

Set name to whatever you called the Worker. With this file in place, the deploy step just reads the files in dist and uploads them. You’ll see a line like “Read 78 files from the assets directory” in the log, and no mention of the Astro setup.

One more gotcha here. If a deploy fails and you push a fix, don’t hit Retry on the failed build. Go back to the deployment list, find the build for your newest commit and watch that one.

When it goes green you’ll have a working site on a workers.dev address.

Step 4: Point your domain at it

In the Worker, open Settings, then Domains & Routes, then Add, then Custom domain. Add your bare domain, then add the www version too. Cloudflare creates the DNS records and the HTTPS certificate for you. The certificate can take a few minutes.

Test in a private window, since your browser may hang on to the old page for a while. Then send yourself an email to make sure mail still arrives.

What it costs

The domain renewal. That’s the whole bill.

GitHub is free for this. Cloudflare’s free plan covers the DNS, the certificate and the hosting, and static file requests don’t count against any limit. Builds on the free plan are capped per month, but a personal blog won’t get anywhere near it.

Writing posts from here

Each post is a Markdown file in src/content/posts/. Add one, commit, push, and the site rebuilds within a couple of minutes. You can even do it from GitHub’s web editor without installing anything.

If you want to write something without publishing it yet, put draft: true in the frontmatter. It builds but stays off the site until you remove it.

If you follow along and something breaks in a way I didn’t cover, I’d like to hear about it.


Share this post:

Previous Post
Hello from the void