Deploying a Hugo blog with gitreceive

Published

This blog post is actually one I meant to write a long time ago, but always put off. I'm going to describe how to use gitreceive to deploy a blog that's built using Hugo. I find the Heroku-style of deploying using git push nice in some cases and this is a nice example of using gitreceive as any. Obviously other static blogging tools can be used.

First, setup the server

We need to create a user on the server, grant it access to deploy the blog and add the SSH public keys.

sudo useradd -m hugo
sudo install -d -m 755 -o hugo -g hugo /var/www/html/blog
sudo install -d -m 700 -o hugo -g hugo ~hugo/.ssh
sudo install -m 600 -o hugo -g hugo /dev/null ~hugo/.ssh/authorized_keys
echo 'command="GITUSER=hugo gitreceive run %s %s" ssh-ed25519 AAAAC3....' | sudo tee ~hugo/.ssh/authorized_keys

Now we'll install git, gitreceive and Hugo.

sudo apt-get install -y git
cd /usr/local/bin
curl -L https://github.com/gohugoio/hugo/releases/download/v0.83.1/hugo_0.83.1_Linux-64bit.tar.gz | sudo tar -xz
sudo curl -L https://raw.github.com/progrium/gitreceive/master/gitreceive -O gitreceive
sudo chmod +x gitreceive

Create the receiver script with the following content at /home/hugo/receiver and mark it as executable:

#!/bin/sh
set -eu

repo="$1"
mkdir -p "/var/tmp/gitreceive/$repo"
echo '----> Unpacking'
tar -x
echo '----> Building blog'
hugo --cleanDestinationDir
echo '----> Deploying blog'
rm -rf /var/www/html/blog/*
cp -r public/* /var/www/html/blog/
echo '----> Done'

Second, the client side

Actually, this is quite simple, just adding a git remote.

git remote add deploy hugo@example.com:blog

And now let's give it a test.

$ git push deploy
Counting objects: 39, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (31/31), done.
Writing objects: 100% (39/39), 6.55 KiB | 2.18 MiB/s, done.
Total 39 (delta 9), reused 0 (delta 0)
----> Unpacking
----> Building blog
Start building sites 

                   | EN
-------------------+-----
  Pages            |  3
  Paginator pages  |  0
  Non-page files   |  0
  Static files     |  1
  Processed images |  0
  Aliases          |  0
  Sitemaps         |  1
  Cleaned          |  0

Total in 10 ms
----> Deploying blog
----> Done
To blog:blog
 * [new branch]      master -> master

That's it, the blog is deployed. Obviously having the output from the script is useful. We can change the receiver script to do a lot of other things. Running docker-compose build && docker-compose pull && docker-compose up -d can produce a simple and straightforward dev environment. We can make it more general by running a script inside the repo and build a makeshift CI tool. Lastly, I have an Ansible role to do all of the server configuration for you in my GitLab instance.