Building This Blog: Jekyll on GitHub Pages from Zero to 130+ Posts | McGarrah Technical Blog
Engineering deep dives on infrastructure, distributed systems, and AI/ML — from homelab experiments to enterprise architecture.
I’ve been writing about technology since 2004 — first on WordPress, then Blogger, and now Jekyll on GitHub Pages. The migration to Jekyll happened in 2023 when I wanted full control over the site without paying for hosting or fighting with WordPress plugin conflicts.
Two years and 130+ posts later, the blog has grown from a basic theme into a heavily customized platform with Mermaid diagrams, GDPR compliance, Pandoc PDF exports, and an automated SEO pipeline. This post covers how I set it all up — the order of operations, the decisions I made, and what I’d do differently.
For the day-to-day writing reference (markdown syntax, code blocks, diagrams, embeds), see the companion post: How the Sausage Is Made: Every Feature Powering This Jekyll Blog.
Why Jekyll?
After years on WordPress, I wanted:
No hosting costs — GitHub Pages is free
Version control — every post is a Git commit with full history
Markdown — write in a text editor, not a web form
Speed — static HTML is fast, no database queries
Control — no plugin conflicts, no PHP updates, no security patches
The tradeoff is that Jekyll requires comfort with the command line, Git, and Ruby. If you’re reading this blog, you probably have that.
Create the GitHub Pages Repository
GitHub Pages serves a static site from any repository named .github.io. Create the repo, clone it, and you have a working site:
git clone git@github.com:/.github.io.git<br>cd .github.io
GitHub automatically builds and serves anything pushed to the default branch at https://.github.io.
Pick a Theme
Rather than starting from a blank index.html, pick a Jekyll theme. This blog uses the Contrast theme by Niklas Buschmann — minimal, responsive, and easy to extend. I’ve since modified it heavily, but the bones are still Contrast.
The fastest way to start:
Fork or copy the theme repository into your .github.io repo
Run bundle install to pull dependencies
Run bundle exec jekyll serve to preview locally at http://localhost:4000
gem install bundler jekyll<br>bundle install<br>bundle exec jekyll serve
See Running GitHub Pages Jekyll Locally for the full local development setup including Ruby version management.
Initial Configuration
The _config.yml file controls everything. The essential settings to change immediately:
title: "Your Site Title"<br>description: "A brief description for SEO and social sharing"<br>url: "https://www.yourdomain.com"<br>author:<br>name: "Your Name"<br>email: "you@example.com"
plugins:<br>- jekyll-feed # RSS feed<br>- jekyll-sitemap # XML sitemap for search engines<br>- jekyll-paginate # Post pagination<br>- jekyll-seo-tag # SEO meta tags and structured data<br>- jekyll-redirect-from # Redirect support for moved pages
Changes to _config.yml require restarting jekyll serve — it’s not hot-reloaded like post content.
File Structure
After theme setup, the key files:
├── _config.yml # Site configuration<br>├── _layouts/ # Page templates (default, post, page)<br>├── _includes/ # Reusable HTML components<br>├── _sass/ # SCSS stylesheets<br>├── _posts/ # Published articles (YYYY-MM-DD-title.md)<br>├── _drafts/ # Work-in-progress (no date prefix)<br>├── _plugins/ # Custom Ruby plugins<br>├── assets/ # CSS, JS, images, fonts<br>├── Gemfile # Ruby dependencies<br>├── CNAME # Custom domain mapping<br>└── index.html # Homepage
Custom Domain
To serve the site from a custom domain instead of .github.io:
Create a CNAME file in the repository root with your apex domain (no www):
mcgarrah.org
Configure DNS with your registrar:
A records for the apex domain (@) pointing to GitHub Pages IPs:
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
CNAME record for www pointing to .github.io
In the GitHub repository settings under Pages, set the custom domain to the apex domain (e.g., mcgarrah.org) and enable Enforce HTTPS
GitHub handles the Let’s Encrypt certificate automatically. With this configuration, GitHub Pages serves the site from the apex domain and automatically 301-redirects www to the apex.
The GitHub Pages custom domain docs cover the full DNS setup.
I’m currently migrating my domains from Squarespace to Porkbun for better API access and lower costs — relevant if you’re choosing a registrar for a new blog.
The www vs Apex Domain Trap
I ran into a subtle but damaging SEO issue that’s worth documenting. My original CNAME file was set to www.mcgarrah.org, but my _config.yml had:
url: "https://mcgarrah.org"
This created a mismatch across the entire site:
Component<br>Domain Used
CNAME (GitHub Pages primary)<br>www.mcgarrah.org
_config.yml url<br>mcgarrah.org
jekyll-seo-tag canonical URLs<br>mcgarrah.org
jekyll-sitemap URLs<br>mcgarrah.org
robots.txt sitemap reference<br>mcgarrah.org
GitHub Pages treated www.mcgarrah.org as the primary domain and 301-redirected the apex mcgarrah.org →...