Running a Jekyll Blog Locally with Docker - A Zero‑Maintenance Approach

1. The Real Problem Statement (The Why)

I maintain a Jekyll-based blog / GitHub Pages site.
From time to time, I want to:

The key challenge wasn’t how to run Jekyll — it was:

How do I run this project on any machine, today or in the future, with minimal setup and zero dependency pain?



The Complete Code Review Checklist

2. The Two Obvious Choices

When running a Jekyll site locally, there are two standard approaches.

Option A — Native setup (install everything locally)

This means:

Pros

Cons

I had already seen this firsthand:
Bundler version mismatches (Gemfile.lock requiring 2.1.4 while the host had a newer one) caused immediate friction.


Option B — Docker-based setup (containerized)

This means:

Pros

Cons


3. The Decision

I chose Docker (Option B).

The reasoning was simple:

I don’t want to “install and fix Ruby” every time I change machines.
I want a setup where I can clone the repo and run one command.

This aligned with my goal of a zero‑maintenance local development environment.


4. Docker Strategy: Two Variants

Even within Docker, there are two approaches.

Docker Option A — “Zero‑maintenance” runtime container

This is what we initially attempted.

Docker Option B — Custom-built image

I intentionally chose Docker Option A first:

The idea was: “Use what GitHub Pages already provides.”


5. Where Things Started to Break (And Why)

Symptom #1: “The server is running, but the browser shows nothing”

Key Insight
This was not a Docker networking issue.

The port was open, but the application was crashing while handling requests.


6. The Hidden Culprit: GitHub API Calls at Render Time

Digging into logs revealed errors like:

Liquid Exception:
GET https://api.github.com/repos/.../releases
429 – abuse detection mechanism

What was happening?

Important realization
Even though the server starts, every HTTP request triggers a render, and that render was failing.


7. Why This Was Confusing

From the outside:

But HTTP failed because:

Jekyll died while rendering the page

This is a classic case where:


8. Fixing the GitHub API Problem

We had two valid solutions.

Solution 1 — Authenticate GitHub API calls (chosen)

This preserved all GitHub-powered features.

✅ We verified success by checking:

Octokit::Client.new.rate_limit
# limit: 5000, remaining: 4xxx

Solution 2 — Disable GitHub metadata in local dev

For pure content work, GitHub data isn’t always needed.

This makes local dev immune to GitHub API issues.


9. More Issues We Had to Solve (Docker-Specific)

Apple Silicon (ARM) vs Image Architecture

The official jekyll/jekyll:4 image does not provide an ARM build.

Result:

image does not provide the specified platform (linux/arm64)

Fix Run the image under emulation:

platform: linux/amd64

Bundler / Gems Missing at Runtime

At one point:

Bundler::GemNotFound

Why?

Fix


10. The Final, Repeatable Outcome

What we ended up with:

This fully satisfies the original goal:

Run my blog locally on any machine without dependency headaches.


11. Lessons Learned (The Takeaways)

  1. “Port is open” ≠ “Application is healthy”
  2. Jekyll can crash during render, not just at startup
  3. GitHub Pages plugins can cause runtime API calls
  4. Docker simplifies environment management, but:
    • platform mismatches matter,
    • volumes matter,
    • startup commands matter
  5. Local dev ≠ production — configs should reflect that

12. When I Do This Again (My Personal Playbook)


Closing Thought

This wasn’t really about Docker or Jekyll.

It was about designing a development workflow that scales with time and machines, not just one laptop.

Docker (Option A: minimalist runtime container) turned out to be the right choice — once the hidden interactions (GitHub APIs, Bundler state, platform differences) were understood and handled deliberately.