DEV Community

Fernando Paladini
Fernando Paladini

Posted on

Host a Free Ghost Blog on GitHub Pages (Without Paying for a Server)

Ghost is one of the nicest writing experiences in blogging. The catch? A normal Ghost install expects a server, a database, and usually a hosting bill.

GitHub Pages is free and reliable — but it only serves static files. It will not run Ghost for you.

So the real question is not “Can Ghost run on GitHub Pages?”

It is: Can I write in Ghost locally, then publish a static copy of my blog for free?

Yes. And after years of people hitting broken images, localhost links on the live site, and Python 2 install failures, that workflow finally got a proper refresh.

This post walks through the problem, the approach, and how to set it up with Ghost on GitHub Pages v3.0.0 — a major release that replaces the old brittle path with something you can actually maintain in 2026.


The problem in plain terms

You probably want some mix of these:

  • Ghost’s editor and admin UI
  • A public blog URL
  • $0/month hosting
  • No Kubernetes, no managed DB, no “just spin up a droplet”

GitHub Pages is perfect for the hosting part. Ghost is perfect for the writing part. They do not speak the same language out of the box.

The workable pattern has always been:

  1. Run Ghost on your machine (localhost)
  2. Generate a static HTML snapshot of the site
  3. Push that snapshot to a GitHub Pages repo
  4. Repeat whenever you publish a new post

That idea is solid. The tooling around it was the painful part.

What used to go wrong

If you tried this years ago (or inherited an old setup), you may remember:

  • Python 2 / buster dependency hell on modern machines
  • Live pages whose nav or tags pointed to http://localhost:2368
  • Broken images after publish
  • Scripts that published too much (or hung for confusing reasons)
  • Docs that assumed you already knew what a “static generator” was

Those were not niche complaints. They showed up repeatedly as real issues — and they are exactly what v3 targets.


What Ghost on GitHub Pages actually does

Ghost on GitHub Pages is a small open-source toolkit that wires that local-Ghost → static-site → GitHub Pages loop together for you.

At a high level:

Edit in Ghost (localhost:2373)
        ↓
gssg builds static HTML/CSS/assets
        ↓
Push to your GitHub repo
        ↓
Live blog on GitHub Pages
Enter fullscreen mode Exit fullscreen mode

You keep writing in Ghost. Visitors get a fast static site. GitHub hosts it for free.

What’s new in v3.0.0

Version 3 is a real major update after a long stretch:

Before (Classic v2) Now (v3)
Python 2 + buster Node.js + wget only
Fragile link/image rewrite Publishing via gssg
Manual / risky upgrades ./migrate.sh with automatic backup
Sparse docs Plain-English guides in docs/

It also addresses long-standing bugs around localhost links, image paths, install errors, and publishing the wrong set of files. Details live in the changelog and v3 release notes.

Live demos:


Who this is for (and who it is not)

Good fit if you:

  • Want Ghost’s writing UX without paying for Ghost(Pro) or a VPS
  • Are fine editing locally and running a deploy script when ready
  • Prefer GitHub Pages (or can adapt the same static output elsewhere)
  • Use macOS, Linux, or Windows via WSL

Not a great fit if you need:

  • Live server-side Ghost features on the public site (members, dynamic search, server-rendered previews, etc.)
  • Instant publish from any device without touching your machine
  • A fully managed “click publish and forget” SaaS

Be honest with yourself here: this is static publishing with Ghost as the CMS, not “Ghost Cloud for free.”


Tutorial: set up a free Ghost blog on GitHub Pages

Prerequisites

Before installing:

  1. Node.js LTS (v18 or v20) — nodejs.org
  2. wget
  3. A free GitHub account and a public repository for the blog
  4. Internet access for the initial Ghost download

On macOS:

brew install wget
node --version
Enter fullscreen mode Exit fullscreen mode

On Ubuntu/Debian:

sudo apt-get update
sudo apt-get install -y wget
node --version
Enter fullscreen mode Exit fullscreen mode

Create an empty public GitHub repo (for example my-blog) and keep the clone URL handy.

Full checklist: Requirements.

Step 1 — Download v3

Grab the latest release:

github.com/paladini/ghost-on-github-pages/releases/latest

Extract it somewhere memorable.

Step 2 — Install

cd path/to/ghost-on-github-pages
chmod +x install.sh
./install.sh
Enter fullscreen mode Exit fullscreen mode

This takes a few minutes. It installs Ghost locally. Your blog folder ends up at ~/.ghost.

When prompted, you can publish to GitHub immediately or skip and do it later.

Step 3 — Configure Ghost

Open:

http://localhost:2373/ghost

Create your admin account, write a test post, poke around the editor.

Local preview of the site:

http://localhost:2373

Step 4 — Publish to GitHub Pages

If you skipped deploy during install:

cd ~/.ghost
./deploy.sh
Enter fullscreen mode Exit fullscreen mode

The script asks for:

  • GitHub username
  • Repository name
  • Repository URL

Wait ~10 minutes for Pages to catch up, then open:

https://YOUR_USERNAME.github.io/YOUR_REPO

Sanity checklist

  • [ ] Local blog loads at http://localhost:2373
  • [ ] ./deploy.sh finishes cleanly
  • [ ] The GitHub repo has new static files
  • [ ] The public URL loads
  • [ ] Post/tag links do not point at localhost

If something fails, start here: Troubleshooting.

Updating later

  1. Edit at http://localhost:2373/ghost
  2. Publish again:
cd ~/.ghost
./deploy.sh
Enter fullscreen mode Exit fullscreen mode

That is the whole loop.


How publishing works under the hood

When you run deploy.sh, the flow is roughly:

  1. Ensure Ghost is available locally
  2. Use gssg to crawl/generate a static copy of the site
  3. Rewrite URLs so the public site uses your GitHub Pages domain — not localhost
  4. Push only the static output to your configured repo
  5. GitHub Pages serves those files

v3 also includes helpers like scripts/validate-static.sh so you can catch broken links/images before visitors do, plus optional multi-site deploy profiles (deploy.sh --site / sites.conf) if you maintain more than one blog.

Saved deploy settings live in ~/.ghost/deploy.conf, so you are not retyping repo details every time.


Features worth knowing about

Beyond “install and deploy,” v3 ships with:

  • Simpler dependency story — no Python 2
  • More reliable static output — fewer broken images / localhost leaks
  • Migration path from Classic v2./migrate.sh with automatic backup
  • Plain-English documentation — getting started, deploy, glossary, troubleshooting
  • Static validation script — catch bad links/images pre-publish
  • Multiple GitHub repos / site profiles — useful if you run more than one site
  • CI in the project itself — shellcheck + validation tests on the toolkit

If you are on Classic v2 and it still publishes fine, you can stay. Migrate when you hit Python errors, broken assets, localhost links, or you are setting up a new machine and do not want to resurrect Python 2.

Migration guide: docs/MIGRATION.md.


A note on expectations

This project will not magically turn GitHub Pages into a full Ghost server. Comments widgets, membership, newsletters, and other dynamic Ghost features need a real Ghost host or third-party services.

What it does well is the thing many indie writers and side-project blogs actually need:

A pleasant editor locally + a free, fast, public static blog.

If that is your goal, the v3 path is substantially less painful than the Classic era.


Quick links

Questions and bug reports welcome via GitHub Issues. Docs contributions count too — you do not need to be a developer to help.

If this saved you a hosting bill (or an afternoon fighting Python 2), a star on the repo helps other people find it.

Top comments (0)