Tyler Bird If you're into DevOps, have I got a blog for you... hint: it's this one.

Use Git to Deploy Jekyll

I chose Jekyll to help develop new articles because after setting up a few simple requirements the server can be configured to host the website. And then delpoyed to via git. I’ll show you how in this article.

To enable a workflow for my blog that integrates well with workflows I already have on a day to day basis: using a editor, committing to git and pushing changes. I wanted to eliminate the unnecessary overhead of using a browser to build articles.

After reviewing Jekyll’s deployment methods page I chose to implement a git post-recieve hook to handle deploys.

Here’s the ingredients needed to get that going on a server you host.

Server requirements

The software we’ll need to have git build Jekyll each time we deploy with a git hook will be the following:

  • Git 1.9.1
  • Nginx 1.4.6
  • Ruby 2.x

The Jekyll 3 gem requires Ruby 2 1 for installation.

Server install

On the server we’ll setup the easy stuff first. For example on ubuntu 14.04:

sudo apt-get update
sudo apt-get install git -y
sudo apt-get install nginx -y

There’s lots of ways to install ruby out there with ruby version manangers like rvm or rbenv. For simple stuff like this I still prefer to build from source.

Here’s bash script that can do it for us. Create this file as install_ruby.sh:

#!/usr/bin/env bash
apt-get -y update
apt-get install build-essential zlib1g-dev libssl-dev libreadline-dev libyaml-dev libxml2-dev libxslt1-dev libcurl4-openssl-dev libffi-dev -y
cd /tmp
wget ftp://ftp.ruby-lang.org/pub/ruby/2.3/ruby-2.3.0.tar.gz
tar -xvzf ruby-2.3.0.tar.gz
cd ruby-2.3.0/
./configure --prefix=/usr/local
make
make install
gem install jekyll --no-ri --no-rdoc

Now let’s give it executable rights and run it.

chown +x install_ruby.sh
sudo ./install_ruby.sh

The gem command will install the jekyll gem and all dependent software with it that rubygems can install for us.

Install jekyll on the server like so:

sudo gem install jekyll --no-ri --no-rdoc

At this point the software is setup on the server and ready for us to configure a git hook to deploy to.

The following instructions to setup a git hook borrow from the jekyllrb.com website, with my own annotations.

Git post-receive hook

To have a remote server handle the deploy for you every time you push changes using Git, you can create a user account which has all the public keys that are authorized to deploy in its authorized_keys file. With that in place, setting up the post-receive hook is done as follows:

This example presumes a deployer user and example.com DNS entry.

laptop$ ssh deployer@example.com
server$ mkdir blog.git
server$ cd blog.git
server$ git --bare init
server$ touch hooks/post-receive

Before we take further steps some words about what we just created…

blog.git

When we create a blog.git folder it is the folder that hosts the repository on the server. And by naming the folder with an extention it will more closely resemble that of your current origin.

For example:

$ git remote -v
origin	git@github.com:7hunderbird/blog.git (fetch)
origin	git@github.com:7hunderbird/blog.git (push)

Once we’re done we’ll have these in the list:

$ git remote -v
deploy	deployer@example.com:blog.git (fetch)
deploy	deployer@example.com:blog.git (push)
origin	git@github.com:7hunderbird/blog.git (fetch)
origin	git@github.com:7hunderbird/blog.git (push)

git –bare init

Have you ever run git init . and git init --bare to see what the difference is? Create a temporary folder and do it now. Then come back here. See?

Jon Saints put it in a interesting way. Use git init for a working repository and git init --bare for a sharing repository.

We’re not going to be working from this repo, it’s job will be to run a hook when it receives a post-receive hook.

Edit hooks/post-receive

Now we’re ready to jump back in and edit our post-recieve hook. Open the hooks/post-receive file in the editor you’re most familiar with and let’s add the content, then we’ll discuss it’s behavior.

#!/bin/bash

GIT_REPO=$HOME/blog.git
TMP_GIT_CLONE=$HOME/tmp/blog
PUBLIC_WWW=/usr/share/nginx/html

git clone $GIT_REPO $TMP_GIT_CLONE
jekyll build -s $TMP_GIT_CLONE -d $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE
exit

In a moment we’ll be setting up the remote that can push the repostiory. This push will populate the repo that can be cloned to a temporary folder for each jekyll build command to output in the destination public folder. Finally it removes the temporary git clone.

Add git remote

This is the git remote command that will configure your local repository’s ability to use a command to deploy to the server.

laptops$ git remote add deploy deployer@example.com:blog.git

Now when you’re ready you can run git remote -v to confirm the remotes are setup and then deploys run by passing the destination remote and branch git push <remote> <branch>:


git push deploy master

A successfull deploy looks something like this:

→ git push deploy master
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 3.70 KiB | 0 bytes/s, done.
Total 8 (delta 3), reused 0 (delta 0)
remote: Configuration file: /home/deployer/tmp/blog/_config.yml
remote:             Source: /home/deployer/tmp/blog
remote:        Destination: /usr/share/nginx/html
remote:  Incremental build: disabled. Enable with --incremental
remote:       Generating...
remote:                     done in 0.749 seconds.
remote:  Auto-regeneration: disabled. Use --watch to enable.
To deployer@example.com:~/blog.git
   5e809a6..1a1e2cf  master -> master

Errors you receive when you deploy will actually be logged to STDOUT, this made debugging issues easier, even remotely.

Any other problems please feel free to reach out in the comments.

Footnotes