Updating a website on a server can be a tedious and inconvenient process, especially if I want to delete posts. Additionally, I don’t want to deploy a SFTP server and expose the file system to the public network, even though I can update my website by connecting with SFTP in my file explorer.
To streamline the process, I plan to use a Git workflow to automate the deployment. Once I add and push my commits to the server, the blog will automatically build and deploy to an HTTP server without manual intervention.
To get start, let’s install Git and Hexo. My serve is Ubuntu, so I install them with the follow command:
sudo apt install git yarnpkg
In most cases, Linux distributions do not have packages specifically for Hexo. Therefore, I have installed yarn, a Node.js package manager, which we can use to install Hexo later.
Logging into server, locate an appropriate directory to store the repository
for our blog. I will be using directory /blog
in this posts.
mkdir /blog
cd /blog
git init --bare
Now a bare repository is set up in the /blog
directory. It doesn’t
contain a working directory and used to manager the Git history of the files,
just like .git
directory of normal Git repository created using command git init
.
For more information about bare repository, refer to book Pro Git. I highly recommend reading this book, it contains plenty of explanation and examples that are crucial for understanding Git.
To verify the repository is accessible, cloning it from a local machine:
git clone ssh://user@ip:port/blog
Here, I replace user
with my username
in server, ip
with IP of server,
port
with SSH port number used on the server, the following /blog
with
the absolute path of repository on the server.
If you want to create a new user specifically for Git, refer to the book for instructions.
After confirming that the repository is accessible from a local machine, the next step is to set up a hooks to trigger our programs when certain events occurs in the repository, such as a commit or a push. This document has an accurate explanation of Git hooks:
Hooks are programs you can place in a hooks directory to trigger actions at certain points in git’s execution. Hooks that don’t have the executable bit set are ignored.
By default the hooks directory is
$GIT_DIR/hooks
, but that can be changed via the core.hooksPath configuration variable (see git-config[1]).Before Git invokes a hook, it changes its working directory to either $GIT_DIR in a bare repository or the root of the working tree in a non-bare repository. An exception are hooks triggered during a push (
pre-receive
,update
,post-receive
,post-update
,push-to-checkout
) which are always executed in$GIT_DIR
.
If you navigate to the repository directory, you will see a subdirectory called
hooks
, which is intended for storing git hooks:
$ ls /blog
branches config description HEAD hooks info objects refs
Next, setup a post-receive
hooks that will be triggered whenever the blog is
updated on server via git push
. This hooks executes on the remote repository
once all refs have been updated. To create the hook, navigate to /blogs/hooks
directory and create a script named post-receive
with following content:
#!/bin/sh
echo "[1/3] Checkout contain of repository"
blog="/checkout"
mkdir -p ${blog}
git --work-tree=${blog} checkout -f
echo "[2/3] Install dependence of blog"
cd ${blog}
yarn install
echo "[3/3] Build and deploy blog"
yarn hexo generate
rsync -av --delete ${blog}/public/ /var/www/html/
Also don’t forget add executive access for script :) :
chmod +x hooks/post-receive
This script first checks out the contents of the repository, then install the
blog’s dependencies and builds the blog before deploying it to the server using
rsync
. Make sure make script executable by running chmod +x post-receive
.
Make sure to modify this script according to your Hexo blog and HTTP server
configuration.
This is the explanation for -avz --delete
parameter of rsync
command:
-a
: archive mode, which preserves permissions, ownership, timestamps,
and other attributes of the files being synchronized-v
: verbose mode, which shows the progress of the synchronization
in the terminal-z
: compression mode, which compresses the files during transmission to
reduce the amount of data that needs to be transferred--delete
: an option that tells rsync to delete any files in the destination
directory that do not exist in the source directory. This ensures that
the destination directory is an exact replica of the source directory.Now I can add the remote URL to the local Git repository for the blog, you can
replace my-server
with any name that makes sense to you:
git remote add my-server ssh://user@ip:port/blog
Once the remote URL is added, it is ready to push changes to the server by running the flowing commands:
git add .
git commit -m '[add/update/delete] brief description of changes'
git push
This will push the changes to the remote repository. The post-receive
hook on
the server will be triggered automatically after the push, and it will build and
deploy the updated blog.