I have always liked working with Git because it has saved my bacon on several occasions. However, the more I started actively developing with Git and using servers to host different websites I wondered if perhaps there was a better way to get my development and remote servers to stay in continuous sync.
The Gool 'Ole Way
I would at times edit code on my local machine then have to FTP my changes to the remote server and test. It was tedious but at times when I was away from my machine I didn’t have the time to setup a local environment, or would need to make a change for a client quickly so I would edit files on the server itself. (I can hear the screams). So in order to alleviate this issue I started using Git on my remote servers in order to skip this scary issue of having to edit code on a production server with no way to rollback. At least this way I could do a quick
git reset —hard in order to erase my bad mistakes. As time went on this procedure worked great for deployments. I could merge all my changes into a production branch when I was ready and then on the remote server run the
git pull commands in order to pull the code. Needless to say for a deployment schedule having to SSH into the server every time became tedious. So this left with me with only one option, which was continuous deployments through Git web hooks.
First, I reading to see what approaches others had been working on to accomplish this task before trying to write my own. After reading an article by Brandon Summers “Using Bitbucket for Automated Deployments” I attempted to use his approach, but at first it didn’t work. So that started me off an intense battle to figure out how to get this deployment method to work.
Note: this entire process is based on you having SSH access to your server. If you don’t have access then look into getting some. If SSH is a foreign concept to you, then I would recommend against attempting this at all because it can cause serious issues with your server if not done correctly.
What We’ll Cover
- Set up SSH keys so your server can talk to Bitbucket
- Clone your Bitbucket repository on your web server
- Setup a hook on Bitbucket and an associated deployment script on your server
Set up SSH Keys
For your web server to be able to connect securely to Bitbucket or Github we will need to setup a password-less prompt with an SSH key.
On your server navigate to
~/.ssh/ directory you are currently using for SSH. You might need to create this directory if it doesn’t exist.
cd ~/.ssh ssh-keygen -t rsa
The prompt that follows will ask you for a filename. You can opt to leave it as the default (id_rsa) or you can give it a unique name (for this demo I will name mine bitbucket_rsa). I wanted to make sure I knew what the key was being used for in case I forgot or needed to change it. Hit enter when prompted for a password, usually this is not recommended but we need Bitbucket or Github to be able to connect without a password.
Now after that is complete a public and private key pair has been generated. Copy your public key (the file with the .pub extension) and log into your Bitbucket or Github account.
For Bitbucket, navigate to Account > SSH Keys, and Add key. For Github, navigate to Account Settings > SSH keys, and click Add SSH key (in the top right)
Back on your server you will need to tell you server which key to use for the host you want to connect to. The example below shows how you would setup a bitbucket host and for Github just change the Host name and IdentityFile location.
Host bitbucket.org IdentityFile ~/.ssh/bitbucket_rsa
What this will do is that whenever a git command is run it will not prompt for a password.
Clone your repository
You might be tempted to just clone your repository to your main web server directory and while this may b fine, it opens you a huge security risk if a hacker managed to break into your .git directory which could contain passwords, database connections, or other sensitive information. You could use an htaccess file to prevent access to that folder, but if it is ever deleted or corrupted then this will create the security hole again. My server is already set up to prevent this issue, but if you would like to secure that folder directly refer to this article: (How do I prevent apache from serving the .git directory?)[http://serverfault.com/questions/128069/how-do-i-prevent-apache-from-serving-the-git-directory]
Before you go any further, navigate to your repository on Bitbucket or Github and copy the SSH url provided. For Bitbucket it will start with “[email protected]” and for Github will start with “[email protected]”.
git clone [email protected]:username/repository.git .
Create a POST hook
In you web server directly create a folder called “deploy” or something that makes sense to you and create few files:
The HTML file will prevent directory browsing (so you can leave this blank for now) and the htaccess file will be used later to create a security check if someone hits the deploy script directly. The htaccess file and the _deploy.php script are below. I want to thank Brandon Summers directly since this script was originally posted by him and I saw it used quite extensively across direct scripts on Github.
Note: Make sure to change the directory in the htaccess file to point to where you are going to store your htpasswd file. This is important if you want to test directly using a web browser to verify that everything is setup correctly.
BitbucketNow to create the POST hook on Bitbucket go to your repository: https://bitbucket.org/username/repository.com Under Settings > Hooks. Select “POST” from the drop down and click Add hook.
GithubFor Github, visit your repository: https://github.com/username/repository Under “Webhooks & Services”, click Add web hook
In both setups, you will want to add the URL to your deploy script where prompted. Now you are fully setup to use web hooks for your deployments. So now each time you commit Bitbucket or Github will send a POST request to your file, which will in-turn run a git pull on your server.
Access Your Deploy Script via HTTP (with Security)
In the root of your website create a new file called
.htpasswd. The contents of this file will be used to access the deploy script when it is run directly. So if you want to run a deploy by hand you can also do this and skip setting up the web hook method if you want. The contents of this file can be created using a HTPASSWD Generator.
Note: Make sure to point your htaccess file that you created in the deploy folder to point to this file.
Another level of security would be to rename your deploy.php file to something less descriptive and harder to remember. For all my deployments I used an MD5 hash to encrypt the file name and make it almost impossible to figure out. Plus with the added security of a password protected prompt you can ensure that your deploys are protected. You can use the Miracle Salad’s md5 Hash Generator to make a quick hash.