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.