Auto Update Site from a Git Push
Tags: git, hooks, hugo, publish
Published: 2021-06-24 21:54:21


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](https://www.linode.com).

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.

```shell
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.

```shell
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.

```shell
#!/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
```
**Footnote**[^1]
[^1]: This script and idea was taken from [Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-hugo-site-to-production-with-git-hooks-on-ubuntu-14-04)  

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.  

**Note**
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:
```shell
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
```shell
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.