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:
Back on the server paste your public key into 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
#!/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
<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!
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!