Deploy Hexo Blog in VPS using Git

Oct. 17, 2021, edited on Mar. 21, 2023

1 Why using Git?

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.

2 Create a Git repository on Server for Blog

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.

3 Set up the Git Hooks

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:

3 Updating the Blog via Git on a Local Machine

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.