Since gitorious has now shutdown I've (finally!) moved the qcontrol homepage to: http://www.hellion.org.uk/qcontrol.
Source can now be found at http://git.hellion.org.uk/qcontrol.git.
Since gitorious' shutdown I decided it was time to start hosting my own git repositories for my own little projects (although the company which took over gitorious has a Free software offering it seems that their hosted offering is based on the proprietary version, and in any case once bitten, twice shy and all that).
After a bit of investigation I settled on using gitolite and gitweb. I did consider (and even had a vague preference for) cgit but it wasn't available in Wheezy (even backports, and the backport looked tricky) and I haven't upgraded my VPS yet. I may reconsider cgit this once I switch to Jessie.
The only wrinkle was that my VPS is shared with a friend and I didn't
want to completely take over the gitolite and gitweb namespaces in
case he ever wanted to setup git.hisdomain.com, so I needed
something which was at least somewhat compatible with
vhosting. gitolite doesn't appear to support such things out of the
box but I found an interesting/useful
post
from Julius Plenz which included sufficient inspiration that I thought
I knew what to do.
After a bit of trial and error here is what I ended up with:
Install gitolite
The gitolite website has
plenty of documentation on configuring gitolite. But since gitolite is
in Debian its even more trivial than even the quick install makes out.
I decided to use the newer gitolite3 package from
wheezy-backports instead of the gitolite (v2) package
from Wheezy. I already had backports enabled so this was just:
# apt-get install gitolite3/wheezy-backports
I accepted the defaults and gave it the public half of the ssh key
which I had created to be used as the gitolite admin key.
By default this added a user gitolite3 with a home directory of
/var/lib/gitolite3. Since they username forms part of the URL used
to access the repositories I want it to include the 3, so I edited
/etc/passwd, /etc/groups, /etc/shadow and /etc/gshadow to say
just gitolite but leaving the home directory as gitolite3.
Now I could clone the gitolite-admin repo and begin to configure
things.
Add my user
This was simple as dropping the public half into the gitolite-admin
repo as keydir/ijc.pub, then git add, commit and push.
Setup vhosting
Between the gitolite docs and Julius' blog post I had a pretty good idea what I wanted to do here.
I wasn't too worried about making the vhost transparent from the
developer's (ssh:// URL) point of view, just from the gitweb and
git clone side. So I decided to adapt things to use a simple
$VHOST/$REPO.git schema.
I created /var/lib/gitolite3/local/lib/Gitolite/Triggers/VHost.pm
containing:
package Gitolite::Triggers::VHost;
use strict;
use warnings;
use File::Slurp qw(read_file write_file);
sub post_compile {
my %vhost = ();
my @projlist = read_file("$ENV{HOME}/projects.list");
for my $proj (sort @projlist) {
$proj =~ m,^([^/\.]*\.[^/]*)/(.*)$, or next;
my ($host, $repo) = ($1,$2);
$vhost{$host} //= [];
push @{$vhost{$host}} => $repo;
}
for my $v (keys %vhost) {
write_file("$ENV{HOME}/projects.$v.list",
{ atomic => 1 }, join("\n",@{$vhost{$v}}));
}
}
1;
I then edited /var/lib/gitolite3/.gitolite.rc and ensured it
contained:
LOCAL_CODE => "$ENV{HOME}/local",
POST_COMPILE => [ 'VHost::post_compile', ],
(The first I had to uncomment, the second to add).
All this trigger does is take the global projects.list, in which
gitolite will list any repo which is configured to be accessible via
gitweb, and split it into several vhost specific lists.
Create first repository
Now that the basics were in place I could create my first repository (for hosting qcontrol).
In the gitolite-admin repository I edited conf/gitolite.conf and added:
repo hellion.org.uk/qcontrol
RW+ = ijc
After adding, committing and pushing I now have "/var/lib/gitolite3/projects.list" containing:
hellion.org.uk/qcontrol.git
testing.git
(the testing.git repository is configured by default) and
/var/lib/gitolite3/projects.hellion.org.uk.list containing just:
qcontrol.git
For cloning the URL is:
gitolite@${VPSNAME}:hellion.org.uk/qcontrol.git
which is rather verbose (${VPSNAME} is quote long in my case too),
so to simplify things I added to my .ssh/config:
Host gitolite
Hostname ${VPSNAME}
User gitolite
IdentityFile ~/.ssh/id_rsa_gitolite
so I can instead use:
gitolite:hellion.org.uk/qcontrol.git
which is a bit less of a mouthful and almost readable.
Configure gitweb (http:// URL browsing)
Following the
documentation's
advice I edited /var/lib/gitolite3/.gitolite.rc to set:
UMASK => 0027,
and then:
$ chmod -R g+rX /var/lib/gitolite3/repositories/*
Which arranges that members of the gitolite group can read anything
under /var/lib/gitolite3/repositories/*.
Then:
# adduser www-data gitolite
This adds the user www-data to the gitolite group so it can take
advantage of those relaxed permissions. I'm not super happy about this
but since gitweb runs as www-data:www-data this seems to be the
recommended way of doing things. I'm consoling myself with the fact
that I don't plan on hosting anything sensitive... I also arranged
things such that members of the groups can only list the contents of
directories from the vhost directory down by setting g=x not g=rx
on higher level directories. Potentially sensitive files do not have group
permissions at all either.
Next I created /etc/apache2/gitolite-gitweb.conf:
die unless $ENV{GIT_PROJECT_ROOT};
$ENV{GIT_PROJECT_ROOT} =~ m,^.*/([^/]+)$,;
our $gitolite_vhost = $1;
our $projectroot = $ENV{GIT_PROJECT_ROOT};
our $projects_list = "/var/lib/gitolite3/projects.${gitolite_vhost}.list";
our @git_base_url_list = ("http://git.${gitolite_vhost}");
This extracts the vhost name from ${GIT_PROJECT_ROOT} (it must be
the last element) and uses it to select the appropriate vhost specific
projects.list.
Then I added a new vhost to my apache2 configuration:
<VirtualHost 212.110.190.137:80 [2001:41c8:1:628a::89]:80>
ServerName git.hellion.org.uk
SetEnv GIT_PROJECT_ROOT /var/lib/gitolite3/repositories/hellion.org.uk
SetEnv GITWEB_CONFIG /etc/apache2/gitolite-gitweb.conf
Alias /static /usr/share/gitweb/static
ScriptAlias / /usr/share/gitweb/gitweb.cgi/
</VirtualHost>
This configures git.hellion.org.uk (don't forget to update DNS too)
and sets the appropriate environment variables to find the custom
gitolite-gitweb.conf and the project root.
Next I edited /var/lib/gitolite3/.gitolite.rc again to set:
GIT_CONFIG_KEYS => 'gitweb\.(owner|description|category)',
Now I can edit the repo configuration to be:
repo hellion.org.uk/qcontrol
owner = Ian Campbell
desc = qcontrol
RW+ = ijc
R = gitweb
That R permission for the gitweb pseudo-user causes the repo to be
listed in the global projects.list and the trigger which we've added
causes it to be listed in projects.hellion.org.uk.list, which is
where our custom gitolite-gitweb.conf will look.
Setting GIT_CONFIG_KEYS allows those options (owner and desc are
syntactic sugar for two of them) to be set here and propagated to the
actual repo.
Configure git-http-backend (http:// URL cloning)
After all that this was pretty simple. I just added this to my vhost
before the ScriptAlias / /usr/share/gitweb/gitweb.cgi/ line:
ScriptAliasMatch \
"(?x)^/(.*/(HEAD | \
info/refs | \
objects/(info/[^/]+ | \
[0-9a-f]{2}/[0-9a-f]{38} | \
pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
git-(upload|receive)-pack))$" \
/usr/lib/git-core/git-http-backend/$1
This (which I stole straight from the git-http-backend(1) manpage
causes anything which git-http-backend should deal with to be sent
there and everything else to be sent to gitweb.
Having done that access is enabled by editing the repo configuration one last time to be:
repo hellion.org.uk/qcontrol
owner = Ian Campbell
desc = qcontrol
RW+ = ijc
R = gitweb daemon
Adding R permissions for daemon causes gitolite to drop a stamp
file in the repository which tells git-http-backend that it should
export it.
Configure git daemon (git:// URL cloning)
I actually didn't bother with this, git http-backend supports the
smart HTTP mode which should be as efficient as the git
protocol. Given
that I couldn't see any reason to run another network facing daemon on
my VPS.
FWIW it looks like vhosting could have been achieved by using the
--interpolated-path option.
Conclusion
There's quite a few moving parts, but they all seems to fit together
quite nicely. In the end apart from adding www-data to the
gitolite group I'm pretty happy with how things ended up.