Photo by Clint Patterson / Unsplash

You run your blog on Ghost 3.x, 4.x using the Docker image, and you want to migrate to version 5, released in May 2022; this post is for you.

Ghost 5 brings many improvements that enhance the experience of both the blogger and visitors/members. Here are some features released:

  • Multiple newsletters on a single website
  • Offer more ways for your audience to become paid subscribers
  • Support for Grammarly in the Ghost editor
  • Advanced member filtering and bulk actions
  • 12 new editor cards, including gifs, buttons, callouts, audio and video
  • Learn more on this post.

On the technical side, Ghost 5 requires MySQL 8 as the database, meaning that coming from 3.x, or 4.x that use MySQL 5, you need to perform this upgrade while reducing the downtime of your website.

As a great fan of Ghost, I will show how I upgraded my blog.

If you are starting your blogging journey and want to self-host your blog with Ghost, I write a complete guide on how to set it up.

Set up a personal blog with Ghost and Docker
In this tutorial, we will see how to set up a blog with Ghost and Docker. Make it accessible through a subdomain and finally protect it with an SSL certificate from Letsencrypt.

My current setup

I run my blog using Docker Compose, and here is the YAML configuration called blog.yml:

version: '3.1'

services:

  ghost:
    image: ghost:4.47.0
    restart: always
    ports:
      - 8080:2368
    volumes:
      - ~/data/content:/var/lib/ghost/content
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: secret_password
      database__connection__database: ghost
      url: https://blog.tericcabrel.com
      NODE_ENV: production

  db:
    image: mysql:5.7
    restart: always
    volumes:
      - ~/data/db:/var/lib/mysql
    ports:
      - "33060:3306"
    environment:
      MYSQL_ROOT_PASSWORD: secret_password
      MYSQL_DATABASE: ghost
      MYSQL_USER: user
      MYSQL_PASSWORD: user_secret
      

OBVIOUSLY, I CHANGED THE CREDENTIALS

The configuration of this file creates two containers, one for the Ghost and the other for the database of the MySQL 5 image.

To upgrade to Ghost 5, here are the steps:

Back up the running database

All the posts, tags, pages, users, etc... are stored in the database, and we must back them up before upgrading to MySQL 8

MySQL client provides a tool to back up and restore a database called mysqldump. We will install it on the server; follow this post to install it on a Ubuntu server.

Once installed, run the command below to back up the database:


mysqldump -u root -p -P 33060 -h 127.0.0.1 ghost > blog.sql

The database content will be stored in the file named blog.sql.

Create a Docker container from the MySQL 8 image

Execute the command below to start a container from the MySQL 8 image:


docker run --name db-blog -e MYSQL_ROOT_PASSWORD=secret_password -e MYSQL_DATABASE=ghost -v ~/data-db8/db:/var/lib/mysql -p 33070:3306 -d mysql:8.0.30

The most interesting part of this command is the option -v, which specifies the volume path to store the database configuration on the physical host.

By doing this, if we restore the data in the database, stop the container and start a new one with the same volume, the new container will reuse the configuration of the previous image, including the data stored inside.

Restore the data dump in the MySQL 8 database

The container for MySQL 8 is now running; let's restore the data in the file blog.sql inside:


mysql -u root -p -P 33070 -h 127.0.0.1 ghost < blog.sql

Stop the Docker container of MySQL 8

We don't need this container so let's stop and delete it. The database configuration will still exist on the physical in the folder ~/data-db8/db.


docker stop db-blog
docker container prune

Duplicate the Docker-compose

The docker-compose configuration file that runs our blog is named blog.yml let's duplicate it and edit the duplicated one. This will make it easy to rerun the previous configuration if the new one doesn't work.


cp blog.yml blog-upgrade.yml

Upgrade the version of Ghost and MySQL

Open the file blog-upgrade.yml and update the docker image version to match the following:

version: '3.1'

services:

  ghost:
    image: ghost:5.8
    restart: always
    ports:
      - 8080:2368
    volumes:
      - ~/data/content:/var/lib/ghost/content
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: secret_password
      database__connection__database: ghost
      url: https://blog.tericcabrel.com
      NODE_ENV: production

  db:
    image: mysql:8.0.30
    restart: always
    volumes:
      - ~/data/db:/var/lib/mysql
    ports:
      - "33060:3306"
    environment:
      MYSQL_ROOT_PASSWORD: secret_password
      MYSQL_DATABASE: ghost
      MYSQL_USER: user
      MYSQL_PASSWORD: user_secret
      

Pull the Docker image of ghost 5.8

We manually pull the Docker image of Ghost 5.8 to reduce the time it will take to have the blog up and running.


docker pull ghost:5.8

Stop running the blog with docker-compose

This command will make your blog down, so make sure to run it quickly as possible:


docker-compose -f blog.yml down

Start the new docker-compose configuration

Run the command below to start Ghost 5 with MySQL 8


docker-compose -f blog-upgrade.yml up -d

The containers will take 15 - 30 seconds to be up and running.

Navigate to your blog URL, and everything will work as expected 🎉.

Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.