A Git workflow to automate deployment to Web servers


Code, push, deploy: the ideal workflow for shipping code to a development or production environment.

There are various approaches out there which either use cloud based services or self-hosted software, the latter using posted data sent from Bitbucket’s Webhooks. The solution which I am going to illustrate here is a self-hosted option which uses the Webhooks only as a trigger to run a few Git command on the deployment server (e.g. doing a Git reset and a Pull).

All you will need is Git, an online Bitbucket (or Github) account and Shell access to your server.

Reasons for automating your deployment workflow

I still remember the pain from the old days when everything had to managed and uploaded via FTP. It was a lengthy and clunky process which hardly ever worked without having to double-check everything again. Having to check which files had been updated and then having to upload and overwrite the changes.

It caused longer periods of time where the application had to be kept in maintenance mode, restricting user’s access.

Streamline your deployments

In the last few years I have been using my own made solution for automating code deployment and database migrations.  This solution allows to deploy changes to server environments by simply pushing code changes via Git using Bitbucket or GitHub. Different Git branches can potentially deploy to different server environments.

An issue that I used to have at the beginning with this solution was that while my code was getting automatically deployed, I still had to manage database changes manually. Luckily, different web application frameworks generally provide solutions for keeping database changes under revision control as well. I use Yii for most of the applications I work on. This is an excellent PHP MVC framework which works well on LAMP stacks. Yii provides a database migration tool which allows to keep track of database migration history, apply new migrations, or revert existing ones.

Setting up SSH keys

You will need to have an SSH key for the user which runs the webserver (e.g. Apache or www-data). This is so that your server can connect securly to Bitbucket without password prompt.

To do this, run cd ~/.ssh ssh-keygen -t rsa  and press enter when asked for a passphrase. This is so that the key is generated as a passwordless.

Copy the public key and add it into your Bitbucket account in the SSH Keys section.

Back on your server, edit your ~/.ssh/config file to add bitbucket.org as a host. This ensures that the correct key is used when connecting by SSH to bitbucket.org.

Preparing the repository

Before being able to run Git pull, you will need to initialise the Git repository. For security reasons, the .git directory part of the repository must not be contained in the public website directory (public_html or www). To do this you can either create a bare repository or change the webserver’s configuration to use a specific sub-directory contained within the repository.

Run these commands

mkdir {application_container_dir}
chown -R apache:apache {application_container_dir}
cd {application_container_dir}
git clone {repository_url}
git init .
git remote add -t \* -f origin {repository_url}
git checkout master

How to setup the deployment script

Decide which branch you want to have deployed to your environment. For example I use dev for a remote server development site and prod for the production website.

You will need to have a script somewhere safe on your server which is listening for POST requests from your Git hosting service. I have prepared a small PHP script which runs the deployment the commands via shell. It is important to block out any requests that are not made from Bitbucket’s servers. This can be achieved by whitelisting Bitbucket’s IP address in an .htaccess file.

This is a summary of what the script does:

  1. Changes directory into the directory where files need to be deployed (e.g. /public_html)
  2. Performs a Git checkout of the specified branch
  3. Performs a Git reset (hard)
  4. Pulls the code changes from the specified origin and branch
  5. Runs any other commands needed to perform database migrations

Deploy the script file onto a safe location on your remote server, make sure the script can be accessed by a public URL.

The next part of the instructions are for Bitbucket but they will be very similar for Github.

Enter your Bitbucket repository and then go into Webhooks which is in the Settings section. Add a new Webhook specifying a title for your reference and the URL of your script. You need the Webhook to be triggered on Push actions, so the other default settings are all good.

Save the settings and then give it a go by trying to push something to your Bitbucket repository.

No Shell access?

Unfortunately for this solution you need to have Shell and root access to your deployment environment. If that is not possible, then there are cloud based services out there which allow a similar deployment workflow. What these services do is to link your Git branches to your deployment environment and changes happen automatically by using FTP. I use Deploybot for a project which is run on a server where I don’t have Shell access.

 

And what solution do you use? It would be interested to discuss this and see which pro and cons or other solutions there are out there.

Leave a Reply

Your email address will not be published. Required fields are marked *