Auto Update Site from a Git Push

Pushing directly from Dev Server to Remote Production Server

Hi,

For a little while now I have been thinking about moving my personal blog to a self-hosted service. One of the options I have been considering is Linode.

As part of this idea. I wanted to see how I might be able to automate some of the processes. This is just a write up on one of my ideas so far.

Idea

The basic idea is pretty simple. After I have created and edited a post. I will push the updates to the remote hosting server. It will then rebuild the site on the hosting server and update the site. At the moment I use Hugo as my static site generator. As part of that I am looking at using a docker image with let’s Encrypt and Nginx. I may cover that in a future post.

Requirements

  • Actions must be done by unprivileged users.
  • rsync is installed
  • git is installed
  • hugo is installed (This would change if you were using a different site generator)

Remote Server Environment

I am going to assume you have an existing unprivileged user. So I will not cover that here. If you need help. Google can be your friend.

The remote server will have two main directories.

  1. Bare git Repo to accept the push from my local development environment.
  2. Normal directly from which the site will be served by the chosen web server.

In my case I chose to create /var/www/ and var/repos. These directories are owned by root. Below these I created the actual folders that git and the web server will use.

WWW

Here I created a folder using the name of my domain.

sudo mkdir -p /var/www/[domain-name]
sudo chown [myuser]:[myuser] /var/www/[domain-name]
chmod 755 /var/www/[domain-name]

The last two commands change the owner of domain-name so that my unprivileged user will have access to this directory. Only the owner will have write access. But anyone can read. This is important as the web server will probably be a different user.

Repos

Here we create the directory for storing git repos. And specifically the repo directory for the site. We also make the directory a special git directory.

sudo mkdir -p /var/repos/[domain-name].git
sudo chown [myuser]:[myuser] /var/repos/[domain-name].git
cd /var/repos/[domain-name].git
git --bare init

post-receive hook

We need to create a post-receive hook that will be triggered when we receive a push from our development server.

#!/bin/bash

DOMAIN=[domain-name]
GIT_REPO=/var/repos/[domain-name].git
WORKING_DIRECTORY=/tmp/$DOMAIN
PUBLIC_WWW=/var/www/$DOMAIN
BACKUP_WWW=/tmp/$DOMAIN-backup

set -e

rm -rf $WORKING_DIRECTORY
rsync -aqz $PUBLIC_WWW/ $BACKUP_WWW
trap "echo 'A problem occurred.  Reverting to backup.'; rsync -aqz --del $BACKUP_WWW/ $PUBLIC_WWW; rm -rf $WORKING_DIRECTORY" EXIT

git clone $GIT_REPO $WORKING_DIRECTORY
# Add any git submodules here so that they are included during the build.
git clone https://github.com/[my sites theme] $WORKING_DIRECTORY/themes/[my theme name]
rm -rf $PUBLIC_WWW/*
hugo -s $WORKING_DIRECTORY -d $PUBLIC_WWW -b "http://${DOMAIN}"
rm -rf $WORKING_DIRECTORY
trap - EXIT

Footnote1

This script basically clones the default branch into a /tmp/ directory. Collects the required theme module and then has hugo build the site directly into the live site folder. There is an issue that if you remove any content from your git repo. It will not be removed from the live site with this approach.

This script could be improved by building the site in another temp directory, and then using rsync to copy this into the live site directory whist deleting any missing files and or folders. Though I did not create this script myself.

Local Development Environment

This part is pretty straight forward. We are simply going to add a new remote repo.

Inside our development git repo we can simply issue the command:

git remote add prod [myuser]@[host]:/var/repos/[domain-name].git

This will allow us to push our update directly to the live web server just by using the command

git push prod

But before we can do this we need to setup our ssh key access.

SSH Access

Regarding SSH. There are many great guides online for this. So I will just suggest that you take a look around.


  1. This script and idea was taken from Digital Ocean ↩︎


See also