In this article I describe my approach to deploying new versions of a personal web application, running under Lighttpd and using Perl as its back-end. The same approach can possibly be used for similar scenarios.

I use Git to track changes in my code and files. This specific web application resides on a checked-out Git repository on the deployment server.

Git is able to call a post-update hook, which runs after the updates have been received. I use this to check out the new version of any changed files, and restart/reload the webserver in order to load the new version of the code, templates, or both.

This hook could be expanded to cover schema changes and similar updates.

Deployment overview

The web application is found on the deployment server, on the user webapp's home directory, /home/webapp. The web application is checked-out in a directory named after it, webapp. The web application runs off the checked-out "live" branch of the Git repository. Another branch, "alpha", is also checked out as webapp-alpha and is used for alpha testing of the webapp.

Lighttpd is configured (in /etc/lighttpd/conf-enabled/999-webapp.conf) to use /home/webapp/webapp/htdocs/ as the document root for the webapp site, and /home/webapp/webapp/webapp.fcgi as the fastcgi backend. Similarly, another 999-webapp-alpha.conf is created to allow the alpha version to also be available (although with less fcgi backends).

A manual approach

If I wanted to deploy manually a new version to the live server, I would push the changes from the development environment to the bare Git repository, then log on the alpha server and pull these changes, then restart the ligttpd server and test the changes. If all were well, the alpha branch would become the live branch which would then be pulled from the live server, the lighttpd server restarted, and the new code would be live.

The post-update hook

I use the hook at git-post-update-hook-restart-lighttpd.txt both for the alpha and the live branches.

The hook is as follows:

#!/bin/sh
# stick in .git/hooks/post-update and make executable

echo "*** $USER: updating server info..."
git update-server-info 2<&1

unset GIT_DIR
cd .. # runs from .git/

echo "*** $USER: hard resetting..."
git reset --hard 2<&1

echo "*** $USER: reloading lighttpd..."
# on /etc/sudoers:
# webapp ALL=NOPASSWD: /usr/sbin/service lighttpd reload
sudo /usr/sbin/service lighttpd reload 2>&1

echo "*** $USER: post-update hook done ***"

This requires /etc/sudoers to be modified to allow the webapp user to execute the command to restart the lighttpd server.

The workflow

The workflow assumes the following:

  • The "master" branch is the one that is deployed to the alpha server
  • Features are deployed in branches created off of the master branch, then rewound and merged to master, tracking via --no-ff the merge to better be able to undo it
  • The "live" branch is nothing more than a blessed point of the "master" branch
  • Development begins at whatever point "live" is

The development/deployment workflow thus is as follows:

(master)    $ git checkout live ; git checkout -b feature_a
(feature_a) $ $EDITOR lib/Webapp.pm # change things
(feature_a) $ git commit lib/Webapp.pm -m "Changed things"
(feature_a) $ # ready to test the feature A on alpha
(feature_a) $ git checkout master ; git merge --no-ff feature_a
(master)    $ git push alpha master # the alpha hook runs and deploys
(master)    $ # if all well and feature can be pushed to live,
(master)    $ git checkout live ; git pull --rebase live/live
(live)      $ git merge --no-ff alpha # merge the new changes
(live)      $ git push live live # the live hook runs and deploys
(live)      $ git checkout master ; git pull --rebase live/live
(master)    $ git push origin --all # save development status on origin repo