Welcome to my blog! Rather than just saying “hello,” I figured the first post should actually be useful — so here’s a full breakdown of how this site was built and deployed.

The Tech Stack

LayerTool
Static site generatorHugo
ThemePaperMod
HostingGitHub Pages
CI/CDGitHub Actions
Dev environmentGitHub Codespaces
Custom domainblog.brianli.net via DNS CNAME
TLSLet’s Encrypt (auto-provisioned by GitHub)

Total cost: $0 (aside from the domain itself).


Why Hugo?

Hugo is a static site generator written in Go. It takes Markdown files and turns them into a fully static HTML site — no database, no server-side runtime, no attack surface. Builds are fast (we’re talking milliseconds for small sites) and the output is just files you can host anywhere.

The alternative I considered was Next.js, but that felt like overkill for a personal blog. Hugo keeps things simple.


The Theme: PaperMod

PaperMod is a clean, minimal Hugo theme with good defaults out of the box: dark/light mode toggle, reading time estimates, code copy buttons, breadcrumbs, and fast load times. It’s added as a Git submodule, which means the theme lives in its own repo and is pinned to a specific commit:

git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod themes/PaperMod

Using a submodule keeps the theme code out of this repo while still locking it to a known-good version.


Hosting: GitHub Pages + GitHub Actions

The entire build and deploy pipeline is a single GitHub Actions workflow (.github/workflows/hugo.yml). Every push to main triggers it:

  1. Build job — installs Hugo Extended v0.145.0, checks out the repo (including the PaperMod submodule), and runs hugo --minify to produce the static site in ./public/.
  2. Deploy job — takes the built artifact and pushes it to GitHub Pages via the official actions/deploy-pages action.

No manual FTP, no S3 bucket, no Netlify account needed. Push to main and the site is live within ~30 seconds.


Custom Domain Setup

GitHub Pages serves the site at lbrian357.github.io by default, but I wanted it at blog.brianli.net. The setup is straightforward:

  1. Add a CNAME file to the static/ folder containing blog.brianli.net — Hugo copies it to the root of the built site, and GitHub Pages reads it automatically.
  2. In the DNS settings for brianli.net, add a CNAME record:
    bloglbrian357.github.io
  3. In the GitHub repo’s Settings → Pages → Custom domain, enter blog.brianli.net.
  4. Check Enforce HTTPS — GitHub auto-provisions a TLS certificate via Let’s Encrypt once DNS propagates.

DNS propagation can take anywhere from a few minutes to 48 hours depending on the registrar and TTL settings.


The Dev Environment

Everything was built inside a GitHub Codespace — a cloud-hosted VS Code instance with a full Linux environment. No local installs required. GitHub Copilot helped scaffold the initial config and workflow file.


What’s Next

This is post one. Future posts will cover whatever I’m working on — engineering, projects, and things I find interesting. If you want to follow along, the source for this site is public at github.com/lbrian357/brianli-blog.