There are many (maybe too many) options when it comes to technical solutions to build a website; if you want a free, simple way to put your blogs out for the world to see, GitHub Pages may be the way to go. I’m going to show you how to set up a blog in a few easy steps, with the express goal of getting your website up and running in an afternoon. To follow this guide, you should be somewhat familiar with Git, GitHub, and Docker.

When I decided I wanted to write this I was a bit overwhelmed with alternatives. I settled for GitHub Pages because at the time it appeared to require just a few steps to get it to work. By default, GitHub Pages uses Jekyll to generate a static site, but here I’ll show you how to build a site with Hugo. To make things easier (easy as in self-contained, organized, clean) we will be running Hugo inside a Docker container.

Create a Docker container

Assuming you have already installed Docker, go ahead and create a new directory; I’ll be naming it hugodocker. Here we will add a Dockerfile with the following content:

FROM klakegg/hugo:0.72.0-alpine
  
RUN apk add git

There is no official Hugo Docker image, but the good people at Hugo recommend you check out this repo by klakegg.

To build the Docker image, we will write a short bash script. I like to call these scripts build.sh; I also like to have all these docker commands written down in scripts because that way I don’t have to remember them, and I can also use git to manage any changes to them.

#!/bin/bash
  
docker build --tag hugodocker:0.1.0 .

Once you have built your Docker image, you can run it interactively. Again, we will write a script that will take as an argument the path to your blog. Let’s call this script run.sh.

#!/bin/bash

if [ -z "$1" ]
then
    echo 'use: ./run.sh <PROJ-DIR>'
    exit 1
fi

cd $1

docker run --rm -it \
    -v $(pwd):/src \
    -p 1313:1313 \
    --dns 8.8.8.8 \
    hugodocker:0.1.0 \
    shell

The most important things here are the docker run flags: -v mounts your blog’s directory on the Docker container, -p binds the container’s 1313 port to your host machine’s 1313 port, and (at least in my experience) --dns is required to resolve a hostname such as github.com from within the Docker container.

Make a new website with Hugo

Go ahead and create a new directory for your blog; mine will be called smallblog. Run your Docker container with $ ./run.sh smallblog/ and once you’re in the container check that it has everything we need: type $ hugo version and $ git version. At the time of writing, I’m running Hugo 0.72.0 and Git 2.24.3.

Create a new site

Here I’ll be summarizing the instructions from Hugo’s Quick Start guide. First, you need to tell Hugo that you want to create a new site right where you are (inside your Docker container your current working directory should be /src). Type $ hugo new site . and don’t forget the . (period). Now you have a config.toml file and a bunch of directories.

Add a new theme

There are many Hugo themes available for free from https://themes.gohugo.io/. I use Radek Koziel’s hello-friend theme. Once you have chosen a theme, you’ll need to start a new Git repo in your current directory with $ git init and then add the theme as a submodule with $ git submodule add https://github.com/panr/hugo-theme-hello-friend themes/hello-friend.

To use the theme edit add a line with theme = "hello-friend" at the end of your config.toml file.

Run the Hugo server

Hugo comes with a web server so you can run your website locally before deploying it to GitHub Pages. To run it, simply type hugo server and open http://localhost:1313/ in your web browser. Before we add any content to your website, you should know that new posts are labeled as “drafts”, so if you want to preview them locally you must tell Hugo to include drafts by including the -D flag: $ hugo server -D. For more on the hugo server command, check the official documentation.

Add a new post

To create a new post just tell Hugo to $ hugo new posts/my-first-post.md. This will create a new Markdown file inside content/posts. See how the file is currently labeled as a draft (don’t forget about this little detail as it is very important). If we run the server again but include draft posts, you’ll see it on your website!

Deploy to GitHub Pages

Now we’re almost set to deploy your newly created site to GitHub Pages. We’re gonna try to get it to work, and see why it’s still not quite ready. The GitHub Pages website shows how to create a new site. Here I’m assuming we’re creating a Project site which we’ll call smallblog.

Go to github.com and create a new repository, name it smallblog, and don’t worry about it being public or private (it doesn’t matter). Go back to your Docker container and a new Git remote: $ git remote add origin git@github.com:MooreMachine/smallblog.git. Push your changes with $ git push -u origin master.

Navigate to your GitHub repository’s settings and to the GitHub Pages section. Under Source choose master branch. Then go to your site’s URL (check out https://mooremachine.github.io/smallblog/ for an example). You should be greeted by a 404 webpage, so how can we fix this?

When you’re using Hugo and GitHub Pages, you’ll have to tell GitHub to build your site from your repository’s master, but also to check a docs/ directory for your static files. By default, Hugo puts these files in a place called public/. Check it out for yourself: go to your Docker container and type $ hugo. This will build your static files.

To build your site’s files in a directory that is not public/, add the following to your config.toml file:

publishDir = "docs"

Remove the public/ directory and build your files again with $ hugo, and you’ll see a docs/ directory containing .html, .css, .xml, .js, and .woff* files. Commit and push these new changes to your GitHub repository. Go back to your repo’s settings page and configure it to build from master and the docs directory.

Try reloading your website and see what happens. You’ll still get the same 404 error page. Even if you delete your cookies you won’t be able to see your blog. Why? Because you should change your baseURL to https://username.github.io/smallblog/ in your config.toml file. I tried multiple different options (you can check out my repo’s Git history) when setting the baseURL but some things would break my site on GitHub Pages and others would break my local environment. So just call set your baseURL to https://username.github.io/smallblog/ but know that to test things locally you’ll have to go to http://localhost:1313/smallblog/ (Hugo will still remind you of this).

At this point, you might have realized that while our new website is up and running, we can’t see our first post. This is because the post is still labeled as a draft. Go back to your Docker container and edit content/posts/my-first-post.md and so that you have draft: false. Before rebuilding your changes you should delete your docs/ directory. Running hugo won’t delete previously generated files, so you have to do that yourself.

Once you have deleted your old docs/ files and built new ones with hugo, push them to GitHub and see your website. Now you’re all done!

Summarizing

Hopefully you’ve found it easy to create a blog using GitHub pages. If you want a quick (incomplete) recap of what we did:

  1. Start by getting Hugo to run inside a Docker container
  2. Create a new directory for your blog
  3. Then create a new Hugo site inside that directory
  4. While editing your site you can use $ hugo server -D to run a local server to browse your blog
  5. The trickiest part might be deploying it to GitHub pages, so make sure to save your built web files in a docs/ directory rather than the default public/ directory
  6. Use the right baseURL
  7. Set draft: false when you’re done
  8. And don’t forget to delete any generated files before running hugo and pushing the final version of your post