Still updating your website's code by FTPing single files? Try converting your site to deploy via Git for fun and profit!

Updating sites using FTP is a slow process which is easily broken - you might forget to upload a file, or overwrite the wrong one, or the connection might drop while you're mid-transfer and so on, leaving your site in a sort-of-in-between state which takes a lot of work to reset. Git is source-control software which tracks all the changes to your files, and while the main purpose of source control is to provide a safety net by allowing any changes to be reversed, you can also use Git to update your site without having to manually copy every changed file over.

Deploying through Git is much nicer than FTP:

  • Git pushes are atomic - i.e. you are guaranteed that either all the updated files are transferred or none of them are, so you know the precise state of your site.
  • You can use a single command to update your entire site, rather than copying every single individual file.
  • You know that all of your changes will be added to the site, so you won't forget anything.

If you've ever created an app on Heroku, you'll be familiar with deploying code using Git, and it's (fairly) straightforward to set up on other hosts. As an example, I'll show you how to set up Git deployment on Webfaction (where most of my sites are hosted) and then we'll deploy a basic Express site running on NodeJS.

You will need:

  • A Webfaction account
  • To be familiar with Git
  • To be able to use the terminal
  • To be able to use SSH (you can use Putty on Windows, otherwise it's built-in to most other platforms)

Part 1: Install NodeJS

The first step is to install NodeJS on Webfaction; the simplest way is to follow the instructions here, as taken from various answers on the Webfaction knowledge base. I've replicated the relevant parts below. You'll need to SSH into your Webfaction account, change to the $HOME directory then run the following:

# from https://gist.github.com/marcoslhc/3909289
mkdir -p $HOME/src
cd $HOME/src
wget 'http://nodejs.org/dist/v0.12.0/node-v0.12.0.tar.gz' # check the NodeJS site for the latest version
tar -xzf node-v0.12.0.tar.gz
cd node-v0.12.0

// All of these scripts use "#!/usr/bin/env python". Let's make that mean python2.7:
PATH_BACKUP="$PATH"
mkdir MYPY
ln -s $(which python2.7) $PWD/MYPY/python
export PATH="$PWD/MYPY:$PATH"

./configure --prefix=$HOME
make         # 5.5m
make install

// restore the PATH (we don't need `$PWD/MYPY/python` anymore).
// Then, make sure $HOME/bin is on the PATH
PATH="$PATH_BACKUP"
export PATH=$HOME/bin:$PATH
echo 'export PATH="$HOME/bin:$PATH"' >> $HOME/.bashrc
hash -r

// Set the node modules path
export NODE_PATH="$HOME/lib/node_modules:$NODE_PATH"
echo 'export NODE_PATH="$HOME/lib/node_modules:$NODE_PATH"' >> $HOME/.bashrc

// now install forever module - we'll need this later
cd $HOME
npm install -g forever

Run node -v to make sure node is installed correctly (should output v0.12.0). You'll see we've installed the forever module - we'll use this later to run our Express site.

Part 2: Set Up Applications

The next step is to set up two applications in your Webfaction dashboard; the first is a Git application which will handle the repos and hooks, and the other is the Node application which will serve the Express app.

Create a new NodeJS app in Webfaction, and make a note of the port the application is running on since we'll need to use this later. Make sure you have a domain name set to this application so we can see our changes when we update the site. Next, set up a Git application: follow the instructions here up to and including the 'Creating a New Repository' section. After creating a Git application, we need to create and edit the post-receive hook to update our files after we've pushed changes to Webfaction. Git hooks contain commands which Git will run automatically when you push code to the repo, and we'll use the post-receive hook to move the code to the correct place then restart the app.

Change to your Node app directory in webapps (so something like cd /home/user/webapps/nodeapp) and create a folder callled 'app' - this is where all your site code will live. Next, follow these instructions to set up a post-receive hook, and make sure you're using the correct file paths as described in the answer here. The post-receive hook should be in /home/username/webapps/yourgitapp/repos/appname.git/hooks/post-receive and should look something like this:

#!/bin/sh
GIT_WORK_TREE=/home/username/webapps/myproject/app git checkout -f master
GIT_WORK_TREE=/home/username/webapps/myproject/app git reset --hard

Webfaction automatically created a pair of scripts in your NodeJS app when you set it up - these can be found in webapps/nodeapp/bin and are called start and stop. We'll need to edit these to point to the 'app' folder we just created, and also to use the forever module to keep Express running (which is why we installed forever earlier). Open webapps/nodeapp/bin/start (using nano or vi or similar) and edit it to look like the following:

#!/bin/sh
procs=$(forever list | grep -F /home/user/webapps/nodeapp/app/bin/www)
if [ -z "$procs" ]; then
    forever start -a -o /home/user/webapps/nodeapp/out.log -e /home/user/webapps/nodeapp/error.log --uid "mylovelynodeapp" /home/user/webapps/nodeapp/app/bin/www
fi

A bit of explanation: the #!/bin/sh line tells the script to run this under the Bash shell; the next line checks to see if forever is already running. This is important so that the start script can be called regularly through a cronjob, and won't crash if it's already running. The if statement then tries to start forever if it isn't running and passes in various options:

  • -a: append to logs instead of overwriting
  • -o: path to the output log file
  • -e: path to the error log file
  • --uid: a string to reference your forever process. This is used to stop the process, otherwise you'd have to stop all the forever processes, which is a bad idea if you're running more than one site on the server! The final parameter /home/user/webapps/app/bin/www is the entry point of the Express app; this won't exist on your Webfaction account yet since we haven't deployed anything.

We'll also update the bin/stop file:

#!/bin/sh
forever stop mylovelynodeapp

This file uses the string set in the start file to stop the forever process. We'll use these scripts to stop and restart our Express app once we've pushed some code - the great thing about deploying through Git is that you can configure it to automatically run scripts once it's received code. To do so, we need to go back and edit the post-receive file and add in the pair of scripts:

#!/bin/sh
# /home/user/webapps/yourgitapp/repos/appname.git/hooks/post-receive
GIT_WORK_TREE=/home/username/webapps/myproject/app git checkout -f master
GIT_WORK_TREE=/home/username/webapps/myproject/app git reset --hard

/home/user/webapps/nodeapp/bin/stop
/home/user/webapps/nodeapp/bin/start

This tells Git to update our website's files, then run the stop and start commands which restarts forever, otherwise our updated files wouldn't appear on the site. You can use the post-receive hook to run any script you like - if you were using Django, for instance, you could run the South commands here to update your database, or you could use it to send an email to all developers to let them know that the live site has been updated.

Part 3: Actually Deploying

On your local machine (which I'm assuming already has Node and NPM installed), install the Express generator:

npm install -g express-generator

and then run express app to create a barebones Express application. Run node bin/www to check it's working (runs on localhost:3000 by default). Edit /bin/www to have the port used by the NodeJS application in Webfaction (remember, the one you saved earlier? If not, you can find it in your Webfaction dashboard under 'Applications'), then run the following to create and commit all files to Git:

git init
git add -A
git commit -m "Basic barebones Express app"

We now have a barebones Express website ready to deploy. We need to add a remote to Git which points to our Webfaction Git application - the command should look something like this:

git remote add web username@username.webfactional.com:/home/username/webapps/yourgitapp/repos/proj.git

This adds a remote called web pointing to Webfaction, so now we can run

git push web master

to deploy the site! If everything has worked, then you should see a message telling you what's running on Webfaction - you can now open your Node site to see your Express website running! If you get a 502 - Bad Gateway error then check the port number is correct and that forever is running. You can now update your website on your local machine and use Git to update it.

Set up on a bare server

If you're trying to set up Git deployment on your own server (not Webfaction), then these two guides give a good walkthrough: