Single command deploys are awesome. When setting up a testing or production server, I always setup a script to deploy in a single command because it makes life easier and encourages frequent deploys.
There are many different ways of setting up one click deploys. This tutorial covers how to setup a git postcommit hook that deploys on
git push prod, which is pretty simple to get started with, but won’t scale well once you start running multiple app servers. For alternatives, you might have a look at Fabric or Capistrano.
Setup the git repo on the server
If you don’t already have
git installed on the server,
ssh in and do a
sudo apt-get install git
Now we want to create a git user:
sudo adduser \ --system \ --shell /bin/sh \ --gecos 'git version control' \ --group \ --disabled-password \ --home /var/git \ git
And append your ssh public key to the git user’s list of authorized keys located at
/var/git/.ssh/authorized_keys, creating the file if necessary.
Now let’s create the repository:
cd /var/git sudo -u git mkdir <repo-name>.git cd <repo-name>.git sudo -u git git init --bare
The repository here is bare so that it can accept pushes. See this discussion of bare vs. non-bare repos if you are interested in learning more.
Create a hook
OK so now we want to create the script that will run after a
git push is received.
Create a file called
/var/git/<repo-name>.git/hooks/post-receive and give it these contents:
#!/bin/bash export GIT_WORK_TREE=/var/www/<app-name>/project/ git checkout -f
The above assumes that your server is setup with
/var/www/<app-name>/project/ as the location where your app server will be looking for your code files.
Add execute permissions and make sure it is owned by git:
sudo chmod u+x hooks/post-receive sudo chown git:git hooks/post-receive
The post receive script will be run as git, so we need to make sure that the git user has permissions to write to the
GIT_WORK_TREE, and also that the server can read and write from those directories. To handle this, lets make git a member of the nginx group, and then have the post receive script touch up the file permissions after checkout.
sudo usermod -a -G nginx $USER
Then edit the script to look like this:
#!/bin/bash # Checkout the repo. export GIT_WORK_TREE=/var/www/<app-name>/project/ git checkout -f # Fix up permissions. cd /var/www/<app-name> chmod -R g+w project/* chown -R git:nginx project/*
Prepare development box
Now on your development machine, add the new remote repository and push to it:
git remote add prod ssh://git@<server>/var/git/<repo-name>.git git push prod master
Other deploy tasks
Often there will be other tasks that have to happen during the deploy. Here is an example of another post-receive hook script that I use for one of my Django projects. It collects the static files to prepare them to be served via nginx, runs the database migrations, and installs any new python requirements.
#!/bin/bash # Checkout the repo. export GIT_WORK_TREE=/var/www/<app-name>/project/ git checkout -f # Fix up permissions. cd $GIT_WORK_TREE chmod -R g+w *py chown -R git:nginx *py source ../env/bin/activate # Collect static files ./manage.py collectstatic --noinput -v 0 # Handle DB Migrations ./manage.py syncdb --migrate -v 0 # Update requirements pip install -q -r requirements.txt deactivate
So there it is – a quick way to setup one touch deploys with git.