Operator Error

adventures in software development and continuous learning

Heroku Style Deployment Anywhere

Heroku is quite the interesting topic these days. While there are many strong opinions about the platform itself, I feel the one thing they get right is deployment.

$ git push heroku master

That’s it. Dead simple.

Now there really isn’t any magic behind this, as Heroku harnesses the power of Git hooks. To mimic this behavior, you can use a post-receive hook, which is just a bash script that runs after the entire process is completed and can be used to update other services or notify users. The beauty is that this functionality can easily be replicated for deploying any of your sites.

For this example, let’s keep it simple and deploy a static blog to a single web server.

First order of business is to make sure you can easily SSH onto your server. So if you haven’t already, make sure your SSH public key is copied to your server:

[dan@local] $ ssh-copy-id username@server.org

Now, on your server, we want to create a bare Git repository. This will be the destination repository for when you perform a git push for deployment:

[dan@server] $ cd ~/git
[dan@server] $ mkdir myblog.git
[dan@server] $ cd myblog.git
[dan@server] $ git init --bare

Next thing to do is setup our simple post-receive script. Let’s assume for the sake of this example that our blog is served on our web server from the following directory: /www/myblog.com. First create the hook in your git repository:

[dan@server] $ touch ~/git/myblog.git/.git/hooks/post-receive

Then update the post-receive hook:

echo 'Deploying to Production...'
GIT_WORK_TREE=/www/myblog.com git checkout -f
echo 'Success!'

Ok, so here is where the magic happens. The GIT_WORK_TREE environment variable is used as a destination for your checked out source code, with any changes you might have made. Thus, we are performing a force checkout to the working tree directory (aka deployment)!

NOTE: One side benefit of the working tree approach is that you do not accidentally serve your .git directory!

Now that we have a new remote repository, let’s go ahead and add it to our local git repository:

[dan@local] $ git remote add production ssh://username@remote-server.org/~/git/myblog.git

The last thing left now is to deploy:

[dan@local] $ git push production master
Counting objects: 9, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 455 bytes, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Deploying to Production...
remote: Success!
To ssh://username@remote-server.org/~/git/myblog.git
   52056c4..1b5c293  master -> master

Now this is a very simple example of a deployment script. Feel free to get as crazy as you want…send emails, message chat rooms, call fabric tasks, etc! The sky is the limit, so get as creative as you’d like.

Feel free to fork my Gist to get yourself started!