It was surprisingly easy to migrate my blog out of ghost, but there were a few missed steps along the way. Often, I would find a better way after I had done the heavy lifting.

1. Install Hexo and create the blog

$ npm install hexo-cli -g
$ hexo init myblog
$ cd myblog

2. Install the hexo-casper theme

$ git clone themes/hexo-casper

3. Configure the theme and site

Edit _config.yaml

# Site
title: Anthony Ison
subtitle: Software development and DevOps. Bringing solutions to life.
description: My meandering thoughts on development, devops and technology
keywords: software development,devops,azure,kubernetes,angular,serverless,docker
author: Anthony Ison
language: en
timezone: Australia/Brisbane  # From
root: /

# Set these to create lowercase, title-only permalinks (like ghost)
permalink: :title/
filename_case: 1

# consider creating a folder with each post to hold any assets
post_asset_folder: true

Edit themes/hexo-casper/_config.yaml

4. Migrate posts from ghost to hexo

In Ghost:
Labs > Export content

$ npm install hexo-migrator-ghost --save
$ hexo migrate ghost my-ghost.json


$ npm install hexo-migrator-tryghost --save
$ hexo migrate ghost my-ghost.json


These probably failed because I was running Ghost 2.x and the export format has changed. If you've got an earlier version, maybe this will work for you.

$ docker run -it -v $(pwd):/temp golang
$ go get -v
$ cd /temp
$ ghost-hexo-migrator my-ghost.json


This got a little closer, and actually pulled content across, but now I'm out of options. Fortunately, I don't have many posts and will manually migrate instead. I hope you have better luck.

5. Reattach the post images

Many of the migration tools will bring content across without images. So afterwards, you will need to copy the images in and link them to posts manually.

Also, it's worth configuring an image optimizer, using:

$ npm i hexo-filter-responsive-images --save

Then add to the _config.yaml:

# hexo-filter-responsive-images
  pattern: '**/*.+(png|jpg|jpeg)'
      width: 800
      withoutEnlargement: true
      width: 2000
      withoutEnlargement: true

To each of the blog post headers, add:

image: my-blog-post/small_cover.jpg
feature_img: large_cover.jpg

where cover.jpg is the original image for the post cover.

6. Configure RSS

$ npm install hexo-generator-feed --save

Add this to your _config.yaml:

  type: atom
  path: atom.xml
  limit: 20
  content_limit: 140
  content_limit_delim: ' '
  order_by: -date
  icon: icon.png

7. Configure deploy

$ npm install hexo-deployer-git --save

Edit _config.yaml

  type: git
  branch: master