I have been thinking of making a blog for a while. I wanted to find a blogging platform that was simple, customizable, static content based so that I could host it in GitHub pages, and supported Markdown so that I could easily publish code projects from Jupyter notebooks and R’s knitr. After a bit of searching I decided to go forward with Jekyll which is a Ruby based blogging platform that seems to have the above features.

Why GitHub pages

GitHub provides hosting for static content sites via it’s GitHub pages. This is really convenient as one does not have to bother setting up a production server and the pages are automatically served from a git repository. All you need to do is to push your content into a special repository (more of this below).

What is neat with GitHub pages for Jekyll is that Jekyll based pages can automatically built by GitHub, meaning that the static content is automatically compiled from the Jekyll source files, such as those Markdown files. Given that GitHub was originally built with Ruby On Rails, the famous Ruby based web-application framework, it’s no wonder that GitHub gave the Ruby based Jekyll a special support. However, I ended up not using that neatness due to a missing gem (Ruby library) in the GitHub environment that was required by my custom theme.

Setting up a developer environment

It’s essential to be able to test your site in your local computer. Jekyll is based on Ruby which needs to be installed if you want to compile your blog from the source files. Installing Ruby and learning it’s ecosystem will take some time, so unless you have that ready it is probably the easiest to use Docker instead.

Jekyll has an official docker image that has all the needed components installed. The following instructions will be based on Docker and assumes you have a working Docker installed to your computer and you are using linux. If you are using Windows 10, you can either use the bash shell within Windows or just modify the commands below.

The philosophy behind the Docker commands below is that if we had Ruby environment installed locally, we could just run commands like jekyll new or bundle install to build a new blog or install Ruby libraries (called gems). Now instead we will run such commands with docker run through the container that has the Ruby environment installed.

Creating the initial jekyll source files with Docker

We will use the official Jekyll Docker image to build the initial source files for the blog. You can find the files created in this section from this repository that I created. To start, first create a folder for the blog, e.g. mkdir blog.

The initial Jekyll blog files can now be created into the blog folder with Jekyll Docker image (I used jekyll/jekyll:3.8) by running:

docker run --rm --volume="$PWD/blog:/srv/jekyll" -it jekyll/jekyll:3.8 \
  jekyll new . --skip-bundle

The command mounted your blog directory to /srv/jekyll in the container and then created the blog files with jekyll new. The source files should now appear in your blog folder. Additional info about the command used above can be found from here.

It may be beneficial to open an interactive shell to the container to test the different commands, for instance to open an interactive bash shell type:

docker run --rm --volume="$PWD/blog:/srv/jekyll" -it jekyll/jekyll:3.8 \
  bash

Now you can check the options for jekyll new with jekyll new --help (note that in the first time it will install bunch of gems).

Some files that we will be needing are Gemfile which lists the gems (Ruby libraries) that your project will use and _config.yml which is the Jekyll site configuration file.

Running the server locally with Docker

The fastest way to run the server is to change directory to the blog folder (that contains the source files) and type:

docker run --rm --volume="$PWD:/srv/jekyll" -p 4000:4000 -it jekyll/jekyll:3.8 \
  bash -c "bundle install && bundle exec jekyll serve -H 0.0.0.0"

You should see information about the server staring. If not, make sure you are in the same folder where you have the source files created above (the blog folder in this example). Now you should have your blog running in localhost:4000 so go ahead and type that to your browser’s address bar to test. Details of the arguments to docker run can be found from here.

While the server is running you can edit the different files to see their effect. For instance you can modify the about.md file and see how the About page is changed after you save the changes. Exceptions are the files _config.yml or Gemfile that require restarting the server.

Speeding up the starting of the server

The above process always reinstalls the needed gems to the container based on the official image. A more efficient way is to first create an image that has the needed gems and then use that image. This will actually speed up all the other commands too. Assuming we are in the blog folder, type:

docker run --name blog_server --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:3.8 \
  bundle install

Notice that we removed the --rm argument which would remove the container after execution. Instead we added --name to give the container a name blog_server. Now typing docker ps -a should show you a container with that name. It has all the gems installed and the final step is to make an image of it with docker commit:

docker commit blog_server blog_server

Now we have an image called blog_server that is based on the official image and has all the needed gems installed. You can see this image listed by typing docker images. The server can now be ran using our new image with

docker run --rm --volume="$PWD:/srv/jekyll" -p 4000:4000 -it blog_server \
  bundle exec jekyll serve -H 0.0.0.0

You will notice that server starts in an instant. As long as you keep the image in your computer you can use it to serve the blog. If you at some point update your bundle (Gemfile) you can recreate the image with the steps above.

Customizing the blog

The first thing in customizing the blog is to choose a theme. If you are planning to host in GitHub with automatic compilation, you can choose the theme from multiple options or even use custom themes via the jekyll-remote-theme gem. To test locally you need to replicate the GitHub Ruby environment. Luckily GitHub makes this really easy, you just need to have

gem "github-pages", group: :jekyll_plugins

in your Gemfile and remove the gem "jekyll" line. This will install all the gems in your local environment that are provided at GitHub.

I had already chosen a theme that was not in the list of GitHub supported themes and unfortunately depended on a gem called jekyll-archives that was not available in the GitHub Ruby environment. This caused the post tags to silently disappear from the posts in compilation (luckily I noticed it). I figured the safest and easiest way forward at this stage would be to just build the pages locally, and push the compiled static pages to GitHub. That way I wouldn’t have to worry about what’s available in the GitHub Ruby environment and what’s not. Of course this means more manual work for me, but not that much.

I followed the quick start instructions of the theme to edit my source files.

Hosting in GitHub

The last step is to have GitHub host the compiled pages. GitHub has made this really simple. You only need to create a git repository with a special name <username>.github.io and all the static content you push to it’s master branch will be available at https://<username>.github.com.

A small nuisance in my case is that I need to manually compile the pages and then push the compiled pages to GitHub. To compile the pages with Docker one can either:

docker run --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:3.8 \
  jekyll build

or use the blog_server image created above

docker run --volume="$PWD:/srv/jekyll" -it blog_server \
  jekyll build

The compiled pages are now found from the _site folder. The contents of this folder need to be committed to the master branch of the <username>.github.io repository and pushed.

To automate this I slightly modified the build command to place the files directly to the local clone of the <username>.github.io repository:

docker run -v="$PWD:/srv/jekyll" -v="path/to/github_repo:/srv/site" -it blog_server \
  jekyll build -d /srv/site

Now the compiled static files are automatically placed to the local path/to/github_repo folder. After committing and pushing you should see your blog appearing at https://<username>.github.com.