This article will demonstrate how you can build a deployment pipeline from your local test server to a remote using a git hook called post-receive
. This tutorial is specifically for unix-based systems such as Linux and MacOS but can also be done on Windows too using Putty or even better: the GNU ssh tool for Windows.
The process
- First set up SSH in your server so that you can access the files through your local machine. Normally, with cloud providers, this is fairly straight-forward as they provide a .pem file during the provisioning of the server which can be used to login to the machine directly. However, I would set the server to use my machine's key to let me in and configure the various server values at ~/.ssh/config file for easy access on my local machine with a config that looks like:
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_rsa
Host acme
User root
HostName <server-ip>
The IdentityFile is our generated SSH private key. If you haven't already i.e. the file ~/.ssh/id_rsa is missing, you can create it using the ssh-keygen tool. You can follow Github's tutorial for doing this. And also, setup the config file using:
touch ~/.ssh/config
chmod 600 ~/.ssh/config
Next, I will install the public key into the server's ssh config folder. This can be done manually. Some providers provide a section in their cPanel/admin panels to add this public key. However, I will do this using a tool called ssh-copy-id and using the .pem or .ppk file provided during provisioning of the server:
brew install ssh-copy-id
ssh-copy-id -i /path/to/.pem/or/.ppk/file
What this does it essentially copies your machine's SSH key into the server so that you can directly SSH into it so that you can SSH simply by:
ssh acme
The alternative is to declare the IdentityFile manually each time or another simple way would be to declare the IdentityFile within the server's ~/.ssh/config block like:
Host acme
User root
IdentityFile /path/to/pem/or/ppk/file
HostName <server-ip>
In this case, the server will be kept pure i.e. your public key will not be stored in the server. Either way works for setting up the git hook and making our deployment chain.
- Now that SSH access is set up, we can go ahead and setup a bare repository in our server so that we can make commits to it. First, we ssh into it:
The last command sets up a bare repository with some git hook templates. The post-receive hook that we're going to introduce will NOT exist in the hooks folder (try doing assh acme mkdir web.git && cd web.git git init --bare
ls
to check) but we will create it manually.
I use vim here as my editor of choice, but you can use emacs if you prefer it. Next, I paste the code:cd hooks touch post-receive vim post-recieve chmod +x post-receive
And then save and exit from vim. It is important that this file has the executable permission set which is why there is a 3rd chmod command. In fact, you can run#!/bin/sh GIT_WORK_TREE=’/path/to/public/html’ git checkout -f
./post-receive
command to test if the git hook works. This is because on some shared hosting providers executing scripts is blocked completely. Now cd out and copy the path of this bare repo:cd .. && pwd
Lets assume, for the sake of this tutorial that this path is /home/moz/web.git
- Now that the server side pipeline is setup, all that's left is to point our local project repository to it so we can make pushes to it. Start by CDing to it:
And voila, that's it! You can now run:cd ~/projects/acme-project git remote add web acme:/home/moz/web.git
And it will perform the necessary steps to deploy the project into your public_html folder and it will appear for your users. There is no hard and fast rule that you need to set this remote name as web. Since I work with clients as a freelancer, I typically have 3 remotes: origin, client and web. The origin is my main development private repo which has all the commits, the client remote for is client's private repo for pushing changes whenever the client finishes making a payment, and the web remote for when the client wants me to publish changes.git push web master
Sometimes, you want to run some pre-commands every time a deployment is made. For example, on NodeJS-based apps, you may want to fetch any new packages, so you can do this on the post-receive hook like:
GIT_WORK_TREE=’/path/to/public/html’ git checkout -f && npm install
You can write more code inside that post-receive file, if you'd like, perhaps run tests before making the actual deployment, or to send an email that a deployment was made, or delete a cache folder within your public_html folder each time before deployment.
If you want to know more about git hooks, I would recommend you to read Skay's introductory article on Git Hooks.