Even though there are countless guides for this, I still need a place to document my way of deploying my websites. If it is useful for other people, even better.
Most of my current websites are created with static site generators. In particular with Hugo and Zola. But having to build them locally and then transfer the files to the web server is a tedious and manual task that can be improved upon with the use of git branches and git-hooks.
The basic idea is to use hooks in a git repository to initiate the building of the website with the installed static site generator. It is necessary to have SSH public key auth set up between all involved parties.
Additionally I have a user on the webserver for each website to be able to limit their permissions to the necessary.
Variant 1: Via central repository
The idea is to have a central git server (potentially self hosted) and a clone of the repository on the webser. When new commits are pushed to the
publish branch on the central server, the
post-receive hook will execute a small set of commands. These include pulling the latest commits from the central repository to the working one on the webserver and building the website.
1.git push to `publish` 2.hook ssh +--------+ +----------------+ +-------------+ | client +-----> central server +-----> webserver | +--------+ +--------^-------+ +-------------+ | | | +-------------> working dir | 3.git pull | + | | 4.build | | | v | | website dir | | | +-------------+
hooks/post-receive hook on the central servers repository has the following contents:
echo "Running Hook:" echo "-------------" while read oldrev newrev ref do echo $ref; case $ref in *publish*) echo "DEPLOYING:"; ssh email@example.com\ 'git --git-dir=/home/webuser/aaronlauterer_com/.git\ --work-tree=/home/webuser/aaronlauterer_com pull &&\ cd /home/webuser/aaronlauterer_com &&\ /usr/local/bin/zola build -o /home/webuser/public_html/'; esac done
The following happens if the pushed branch matches the
- An SSH connection with the user for that website is opened to the webserver
gitis being told which
.gitand the working directory to use and to run a pull
- The SSH session is changing directory into the working dir of the repository
- The SSG is called to build the website to the directory from which the webserver is serving the website.
One could add a
git checkout publish to the commands but in my experience it is enough to do it once during the initial setup, after cloning the repository to the webserver.
Variant 2: Directly to webserver
This variant is useful if there is a lot of data to be pushed in the commit and the connection from the central server is not the fastest.
For me this is the situation with my travel blog which contains a lot of photos.
A few hundred MiB per blog post is not unusual.
Instead of pushing to the central server I send the new
publish commits directly to the webserver.
Later, when at home and in the same network as the central git server, I can push the other branches (mostly
master) way faster to the central git server.
To make this work nicely the repository needs to exists two times on the webserver. Once as a bare repository without a working directory, and as a normal one with a working directory which is pulling locally from the bare one.
1.git push to `publish` +--------+ +------------------+ | client +----------> webserver | +--------+ +------------------+ | | | bare git repo | | + | | | 2.git pull | | v | | git working dir | | + | | | 3.build | | v | | website dir | | | +------------------+
To create a bare repository and a local clone from it run the following commands:
$ git clone --bare firstname.lastname@example.org:/travel_blog.git ~/travel_blog_bare.git $ git clone ~/travel_blog_bare.git ~/travel_blog
hooks/post-receive hook in the bare repository looks like this:
echo "Running Hook:" echo "-------------" while read oldrev newrev ref do echo $ref; case $ref in *publish*) echo "DEPLOYING:" && git\ --git-dir=/home/travel_user/travel_blog/.git\ --work-tree=/home/travel_user/travel_blog pull &&\ hugo -s /home/travel_user/travel_blog/ -d /home/travel_user/public_html/ ;; esac done
In the local repository on my computer where I write new blog posts, I have the following remote in the
$ git remote add production email@example.com:travel_blog_bare.git
To push directly to the
production remote run the following command:
$ git push production publish