git-http-backend on shared hosting, with push

This page was originally published on blog.procrastination.nl, which is still on-line for archival purposes.

There are several posts describing how to get git pull using git-http-backend working on shared hosting, for example this post by mobiphil. However, following those steps, I was left with an unclear 'code 22' error when pushing.

In this post, I will describe shortly how I set-up git on my shared hosting account in a way that does allow pushing.

It should be possible to do this without shell access, but I have not tried this.

1. Getting git


Git was not available on the server by default, so I downloaded a reasonable RPM package:


~ $ mkdir git && cd git
~/git $ wget http://packages.sw.be/git/git-1.7.3-1.el5.rf.x86_64.rpm
~/git $ rpm2cpio git-1.7.3-1.el5.rf.x86_64.rpm | cpio -idmv
25926 blocks
~/git $ usr/bin/git
usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
[-p|--paginate|--no-pager] [--no-replace-objects]
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
[-c name=value] [--help]
COMMAND [ARGS]


2. Create a CGI handler script




~ $ cat > public_html/cgi_bin/git.cgi
#!/bin/sh
export GIT_PROJECT_ROOT=/home/me/git/repos/

if [ -z "$REMOTE_USER" ]
then
export REMOTE_USER=$REDIRECT_REMOTE_USER
fi

/home/me/git/usr/libexec/git-core/git-http-backend

Using absolute paths is probably not necessary, but hey, why not.

Important things to notice:

  1. The GIT_PROJECT_ROOT variable should be defined correctly
  2. If you want to export all git repositories by default, add export GIT_HTTP_EXPORT_ALL=T
  3. REMOTE_USER needs to be defined for pushing to work. Due to redirects, sometimes only REDIRECT_REMOTE_USER is defined. Hence, REMOTE_USER will then be set to REDIRECT_REMOTE_USER.
  4. git-http-backend is not in usr/bin but in usr/libexec/git-core


This is enough to get public read access working onder an URL such as http://host/cgi-bin/git.cgi/repos. If you want a nicer URL, read on.

Note: Pushing will fail with error code '22'.

3. htaccess URL rewriting and authentication


At the moment I only have a few repositories, so I chose the following approach. In public_html, create a directory structure git/repos1, git/repos2, etc. In each of these directories, add an .htaccess file:


~/public_html/git/repos1 $ cat > .htaccess

AuthType Basic
AuthName "Git repository I"
AuthUserFile "/home/me/.htpasswds/gitrepos1/passwd"
require valid-user
RewriteEngine On
RewriteBase /git/repos1
RewriteRule ^(.*)$ /cgi-bin/git.cgi/repos1/$1


This will now allow access using the (authenticated) url http://host/git/repos1, which will allow you to push /and/ pull!

4. Preventing direct access to git.cgi


To prevent people from accessing git.cgi directly, I used the following snippet on top of the git.cgi file:

if [[ $REQUEST_URI != /git/* ]]
then
echo Status: 403 Forbidden
echo Content-type: text/plain
echo
echo Direct access to git.cgi is not allowed
exit
fi