The Story
Like any hipster developer, I got caught up hard in the node.js craze circa 2015 and when go started gaining traction, heck I jumped over there too. I first started my blog in an attempt to ‘practice what I preach’ to my peers and young minds that I was hoping to help mould for the best. I think that every developer should have their own blog. Not in a vain attempt to get clicks or ad revenue, but to keep a log of that tough-to-diagnose error that they tried for weeks to diagnose and fix. My blog acts a lot as a personal reference for issues I’ve faced in my coding life and what I did to get around them.
In a silly attempt to get approved for google ads, I deleted several very helpful-for-me posts that google flagged as being too short to allow me to enable ads on my site for. So I deleted them. This is the only real regret I have in my blogging life.
ANYWAYS
That’s why I blog. This is also partially the reason why I’ve switched from Ghost to Hugo. I was hoping to set up google ads on my blog to help pay for my hosting costs. Since I couldn’t get approved for ads, I started exploring different paths.
Github Pages
Github Pages is an offering that allows you to publish a website using git. The name pretty much says it all. The best part: It’s free! The genearl idea is:
- Create a new repository that looks like [yourusername].github.io
- Clone the repo
- Add an
index.html
file with some content - Commit and push
- Navigate to [yourusername].github.io and boom, you have a website!
Based on my understanding, github pages does a great job at hosting up static html files. Since my current blog runs on Ghost which is a client/server architecture, I would need to migrate my blog to a static site generator so I can make use of Github Pages.
Since I have fallen in lust with go, and Hugo is, by their own definition
The world’s fastest framework for building websites
I decided to give it a go!
Setting up Hugo
Since I use my macbook for everything non work-related, I used homebrew to install hugo. There are several installation options located on hugo’s official getting started pages but I elected to use the trusty homebrew option.
brew install hugo
Once that’s all done, you can create a new site by running
hugo new site myepicblog
Next you should initialize your git repo and add a theme. I’m using the theme hugo-notepadium. You can either clone the themes and commit them with your code or use the snazzy git submodules
to load it up during your build phase. I elect to load it during the build phase.
cd myepicblog
git submodule add https://github.com/cntrump/hugo-notepadium.git themes/hugo-notepadium
You can see what you’ve got happening by running hugo server
and navigating to localhost:1313
You should see a static site and some content. Sweet! Our Hugo site is running.
Migrating content
I started to cringe at the idea of manually moving my content from Ghost to Hugo. Ghost’s content is stored as markdown Hugo’s page setup is, as expected, all stored in Markdown while Ghost relies on a database to organize content. Luckily the community came to the rescue! Ghost provides a list of tools developed by the community to help you migrate from different engines to hugo. Luckily, ghostToHugo was there to save my day.
Snag a backup of your ghost blog
Log in to the admin portion of your ghost blog and perform a backup. this creates a .json
file with all of your blog information. You can find detailed instructions over at ghostforbeginners.com. Save the export.json somewhere accessible!
Migrate content
Go ahead and install ghostToHugo
as mentioned above from here. There are many options to install it but I chose to use the go tooling for it.
Go ahead and open a terminal and type go get -u github.com/jbarone/ghostToHugo
Now it’s as easy as running ghostToHugo export.json
. I had to play with the dateformat a bit as my blog apparently didn’t use the default, but you can figure that out if your blog is different. You can configure this with the -d
flag in ghostToHugo
This will create a new hugo site and will put all of your ghost posts in the content
folder. Copy these to your new content
folder from the previous site setup and you could be good to go from here.
Personally, I wanted a bit more organization in my posts. I don’t have a lot, but I have enough where a flat structure wasn’t working for me. Spend some time here organizing your posts structure for your own sanity down the line. I chose to organize my posts with a content/posts/:year/:slug.md
structure.
Hugo is probably refreshing itself so you can see your posts showing up at localhost:1313
as long as your server is still running
For backwards-compatibility…
I have literally one post that anyone ever finds on google. It’s my post on react and indexeddb and it generates an ok number of clicks a week so I don’t want it to get de-ranked. My ghost blog had a very simple permalink setup: /:slug
. Luckily, in ghost I can configure the same thing! In config.toml
I added
[permalinks]
posts = "/:slug/"
and just like that, my posts are all configured the exact same as my old ghost blog. You can play around with that to fit your own use-case.
Now What?
You could be hacky and just initialize your github repo in the public/*
folder, add the contents and push… but we’re devs and we like to make things automated and slick.
GitHub setup
We are going to need…
- a repo for your blog’s source control. I chose
github.com/jimdhughes/blog
(it’s private) - a repo for your published site. I chose
github.com/jimdhughes/jimdhughes.github.io
- the
.github.io
is very important.
- the
- A secret Token that gives you repo permissions in your account. This will need to be added to the repo identified by #1
- a Github action to build and deploy your static site :)
Let’s do it!
Steps 1 and two are pretty straight forward. Add your hugo site to the repo in #1 and leave the repo from #2 empty.
Create a new personal access token here: https://github.com/settings/tokens/new with
repo
control. It’s going to give you a token. You need to copy this as you’re going to set it up in your project repo.In your project repo, add a ‘secret’ in
github.com/{yourusername}/{yourrepo}/settings/security/secrets
called ‘TOKEN’ and paste the value from step 2Add a build.yml file in
.github/workflows
#build.yml
name: CI
on: push
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- name: Git checkout
uses: actions/checkout@v2
- name: Update theme
run: git submodule update --init --recursive
- name: Setup hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: "0.64.0"
- name: Build
run: hugo --minify
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.TOKEN }}
external_repository: <YOURACCOUNT>/<YOURGITHUBIOREPO>
publish_dir: ./public
user_name: <YOURUSERNAME>
user_email: <YOUREMAIL>
publish_branch: master
Make sure to replace all the
Commit all this code and push it to master and then watch the magic happen :)
An action will be triggered which will build your hugo static site and push all the assets to your .github.io repository. Navigate to
Adding a custom domain
The last step in my migration was to add a custom domain to github pages. To do this you need to do a couple things.
- Log in to your DNS and remove the A Record for your subdomain and add a CNAME record of
.github.io - Once the DNS has propagated, go to the repo of your
.github.io - Press Settings
- go down to Github Pages
- under custom domain, add the name of your domain (mine was blog.jimdhughes.com)
- Once github finds the cname reference in your DNS, it will generate SSL certs. I elected to ‘enforce SSL’ because I think it’s good practice. This will redirect all http requests to your blog to https.
To ensure that the CNAME takes on each deploy, add a static file called CNAME
to the static
folder of your repo and put the cname you want in there. For instance, my static/CNAME
folder has blog.jimdhughes.com
saved in it.
That’s it! A bit of effort and I’ve made my blog a little simpler and saved myself $5 USD / month (which is like $10000 CDN/mo) and I think it feels just a little bit snappier.
Cheers!