After the rise of cloud hosting platforms with multiple environments and slick interfaces it’s easy to forget why we started using them in the first place. A big reason was the ability to sync our development and production environments with Git. Well what if I told you can put git on any old server? That we can do it ourselves and deploy code to production with a simple git push. Yes, you can have your cake and eat it too. Let’s do it.

Note: A requirement of this method is that the Git user and the Unix user who owns the web accessible directory are the same user. With this requirement in place we can work magic.

1. Create the user

We will connect to this user when we push changes up from our local. Create this user like you would any other user on a unix machine:

sudo adduser <username>

Add the ‘sudo’ and ‘ssh’ groups to this user:

usermod -a -G ssh <username>;
usermod -a -G sudo <username>;

2. Give remote user your public key

SSH to the remote server as the <username> user. In their home directory:

mkdir ~/.ssh && chmod 700 ~/.ssh;
touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys;

On your local machine copy the contents of your public key which is usually found at:

~/.ssh/id_rsa.pub

Back on the server paste your public key into authorized_keys:

nano ~/.ssh/authorized_keys

3. Create a bare Git repo

A bare git repo just means that only the “.git” folder exists in the repo’s folder, not the tracked files. The bare git repo becomes the central “host” for the files. This host will then export the tracked files to our web accessible destination directory.

Create a bare repo in your remote user’s home directory:

mkdir .git;
cd .git;
git init --bare;

Note: Though you’ve created this repo in ~/ it will not try to track the contents of your home directory.

4. Push to the bare repo

Add the bare repo “host” as the remote on your local repo:

git remote add origin <username>@<server>:/home/<username>/.git

In the example above <server> is either the server’s IP address or a domain that points to it.

5. On push export to destination directory

On the remote server add a post-receive hook:

nano ~/.git/hooks/post-receive

Paste:

#!/bin/bash
while read old new ref
do
    if [[ $ref =~ .*/master$ ]];
    then
        echo "Master ref received and deployed..."
        git --work-tree=/home/<username> --git-dir=$PWD checkout -f
    else
        echo "$ref received but not deployed."
    fi
done

This script will export Git’s working tree (the tracked files) to /home/<username>. Replace <username> with your destination directory. In my case my repo contains a docroot folder which will be web accessible via Apache, so I have no issue exporting the tracked files directly into my user’s home directory.

Note: As mentioned at the start of the tutorial, the destination directory has to be owned by the Git user in order for Git to have permission to create files and folders. This is why we’re exporting within the user’s home directory.

Save file with Control/Command + O and exit nano with Control/Command + X then make the script executable:

chmod +x ~/.git/hooks/post-receive

Save the file and we’re almost done!

Done

To test things out simply add a dummy commit to your local repo, then git push. Now when the base repo receives the push it exports the latest tracked files to the /home/<username> destination directory. Visit your website’s URL to see the changes!

GIFT

I've made a board game callled GIFT (Good Interesting Fun Times). It's a party game / word game for 2 to 6 players.

Check out the board game!