Monthly Archives: May 2016

Setup git-http-backend on ubuntu / apache

Description

GIT

GIT

Since version 1.6.6 GIT is able to tunnel its native protocol through HTTP or HTTPS. In this post I describe how to set things up so you can use GIT over HTTP(s). As always it is best to make use of HTTPS for security reasons. In this setup we use Basic authentication so you better use HTTP

I also use virtualmin to keep my hosting business running but that should not be a problem when following along with the steps in this post.

Preparation

Ok first of all create a subdirectory in your public_html  (document root) directory. This is where we are going to store the repositories. I suggest you call this directory….git (lowercase). Change directory to your new folder.

mkdir /home/[username]/public_html/git
chown [username]:[username] /home/[username]/public_html/git
cd /home/[username]/public_html/git

Apache htaccess and htpasswd

We are going to create a couple of CGI scripts to have more control over the way the backend is executed. First create a .htaccess file with the following contents:

Options +ExecCGI
AddHandler cgi-script cgi
AuthUserFile /home/[username]/public_html/git/.htpasswd
AuthType Basic
AuthName "Git Private"
Require valid-user

This tells apache that it is ok to execute a CGI script from this folder (line 1, 2). It also tells apache to require a “valid-user”; this user can be found in the .htpasswd file (see below). Now we have to create a password file for the user authentication:

htpasswd -c .htpasswd username
New password:
Re-type password for user username

For testing purpose you could create an index.html  file and try to open that in the browser. The browser should ask your username and password now.

CGI Scripts

Now create a CGI script that will initialise a new bare repository for us to use. Create an init.cgi  script with the following contents (extend parameter checking if you wish).

init.cgi

#!/bin/bash                                                                                                   

# init.cgi
#       Initialise a new git repository. 
# Example:
#       https://[yourdomain]/git/init.cgi?reponame=mynewrepo
# Params:
#       reponame        - the name of the git repository to create
# Remarks
# - The name of the repository may only contain the letters a-z and A-Z
# - The repository should not exist already
echo 'Content-type: text/plain'
echo

source config.sh

saveIFS=$IFS
IFS='=&'
parm=($QUERY_STRING)
IFS=$saveIFS

if [ "${#parm[@]}" -ne "2" ]; then
        echo "Invalid number of parameters"
        exit 1
fi

if [ "${parm[0]}" != "reponame" ]; then
        echo "Invalid parameter name ${parm[0]}"
        exit 2
fi

if ! [[ ${parm[1]} =~ ^[a-zA-Z]*$ ]]; then
        echo "Invalid parameter value ${parm[1]}"
        exit 3
fi

if [ -d "$GIT_PROJECT_ROOT/${parm[1]}.git" ]; then
        echo "Git repository already exists"
        exit 4
fi

mkdir -p "$GIT_PROJECT_ROOT"

git init --bare "$GIT_PROJECT_ROOT/${parm[1]}.git/" 2>&1

echo "Repository created at `date` from $REMOTE_ADDR" > "$GIT_PROJECT_ROOT/${parm[1]}.git/description"
echo "`date` : \"${parm[1]}\" repository created from ip $REMOTE_ADDR" >> "$logfile"
echo >> "$logfile"

exit 0

When you execute this script via the browser (https://yourdomain/git/init.cgi?reponame=[yourreponame] ) a new bare repository is created. The actual repositories are created in the subdirectory repos below the git folder.

The next script will startup the actual GIT http backend. I have wrapped this in an additional script so I could perform some logging. Create a script called git.cgi  in your git directory with the following contents.

git.cgi

#!/bin/bash                                                                                                   

# git.cgi
#       Execute the git http-backend command
# Params
#       As handed by the git client command
# Example:
#       git clone https://[yourdomain]/git/git.cgi/myrepo.git
source config.sh

git http-backend "$@" 2>> "$logfile" || echo failed >> "$logfile"

echo "`date` : git command executed $@" >> "$logfile"

Finally you need a little configuration script, named config.sh , which sets some general parameters. Source is shown below.

config.sh

#!/bin/bash
# When not setting the variable below every repo has to have the magic file
# git-daemon-export-ok. If both are not present a message "Repository not exported"
# shows iup in the log file
export GIT_HTTP_EXPORT_ALL=1
export GIT_PROJECT_ROOT=~/public_html/git/repos
logfile=~/tmp/git_log.txt

Now you can clone a repository by sending your browser to the url

https://yourdomain/git/git.cgi/git/repos/[repo].git

Example workflow

In your browser: https://[yourdomain]/git/init.cgi?reponame=first
In your shell (local): git clone https://[yourdomain]/git/git.cgi/git/repos/first.git
Apply your changes
Add all items to the staging area: git add –all
Commit all changes in the staging area: git commit -am “My commit message”
Push the changes back to the server: git push

That’s all; happy GITing

Share