From Zero to Blog Hero: Hosting your own blog for free with Ghost and GitHub Pages

I often get the question: how do you manage your blog? Do you pay anything for hosting your blog? Do you have some sort of markdown interpreter? How about Search Engine Optimizations, can your blog posts be found online using Google? The short respective answers: Completely managed through a self-hosted Ghost instance, completely free, with rich editor and out of the box search engine optimizations.

So, how does it work? Let's start with a list of requirements:

  • Running Ghost locally via Docker
  • Setting up ghost-static-page-generator for creating static page content
  • Set up Github Pages repository to host your static HTML
  • Optionally: Add CNAME record and update DNS records to host your blog on your custom domain

Running Ghost locally via Docker

After you've setup Docker, run Ghost locally with the following docker-compose.yml, this also sets up a local mysql container for storing your blog posts:

version: '3'
services:
  ghost:
    container_name: ghost
    image: ghost:latest
    restart: always
    ports:
      - 2368:2368
    volumes:
      - ./content:/var/lib/ghost/content
    environment:
      url: http://localhost:2368
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: superS3cretp@ssw0rd
      database__connection__database: ghost

  db:
    container_name: ghost_mysql
    image: mysql:8.4
    command: mysqld --mysql-native-password=ON --authentication_policy=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: superS3cretp@ssw0rd
    volumes:
      - ./data:/var/lib/mysql
Note: remember to change your database password to a strong unique password

With this file in-place, run the container with:

docker-compose up -d

Once the initial run is complete, your Ghost instance will be available at http://localhost:2368.

Set up ghost-static-site-generator

With Ghost running locally, you can convert your blog to static html with gssg. This creates static html and resources for all the endpoints of your blog, which you can then host on a website. Static sites benefit from faster load times and enhanced security since they don't rely on server-side scripting, making your blog not only quick to access but also less vulnerable to web attacks.

To install gssg, with Node.js installed on your local machine, globally install gssg using:

npm install -g gssg

With gssg installed, you can generate the static site with:

gssg --domain http://localhost:2368 --url https://blog.example.com --dest ./static

With the following parameters

  • --domain this is the domain and port hosting your local Ghost instance
  • --url the external URL where your blog will be hosted (e.g., https://blog.example.com)
  • --dest the local path of your static website content

Push blog content to Github Pages

To make your blog accessible to the world, push your static HTML content to a GitHub repository configured with GitHub Pages. GitHub Pages offers a robust, free hosting solution that integrates seamlessly with your GitHub workflow. For most personal and project blogs, it provides a perfect balance between ease of use and functionality.

Follow the instructions below to setup your own GitHub repository with GitHub Pages:

GitHub Pages
Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live.

Add CNAME record to host your blog on your own custom domain

To personalize your blog's URL, you can configure a custom domain by adding a CNAME record. A CNAME record (Canonical Name) redirects visitors from your default GitHub domain to a domain name of your choosing. For instance, instead of your-github-username.github.io, visitors could reach your blog via www.yourblogname.com.

Managing a custom domain for your GitHub Pages site - GitHub Docs
You can set up or update certain DNS records and your repository settings to point the default domain for your GitHub Pages site to a custom domain.

Follow instructions in the link above:

  • Navigate to Settings -> Pages and configure your domain e.g. bart.je which will push a CNAME file to root of your repository with bart.je
  • Add the appropriate DNS records to your domain provider
  • Optionally enforce HTTPS, using either your own SSL certificate, or by e.g. putting Cloudflare in between.