Mercurial, Apache and mod_wsgi

I serve my Subversion repositories using Apache with mod_dav and mod_dav_svn. This is useful because it frees me from either having to run a separate Subversion-specific server which duplicates existing Apache functionality, or SSH which obviously requires shell access for checking out as well as committing code. It was logical to provide a similar setup for my more recently adopted Mercurial repositories, so as promised to Ryan, here's a brief run through of how I did it.

The following Mercurial wiki pages were my main source of information and were useful, if disjointed and partially redundant: Publishing Mercurial Repositories, Publishing Repositories with hgwebdir.cgi, Serving Mercurial repositories with Apache and mod_wsgi.

This is written with Mercurial 1.4.1 and Apache 2.2.14 in mind.

Serving hgwebdir

The recommended method of serving multiple Mercurial repositories is with hgwebdir.cgi. Since the underlying Python application called by this script employs WSGI, it's much more sensible to serve it with mod_wsgi than with mod_python, CGI or FastCGI.  Both hgwebdir.cgi and its mod_wsgi sister hgwebdir.wsgi are included in the Mercurial package and can be found in /usr/share/doc/mercurial-*/ or /usr/share/doc/mercurial-*/contrib .

Configuring hgwebdir

Copy hgwebdir.wsgi to wherever you'll be serving it from, for example /var/www/hg.example.com/cgi-bin/ and make it readable and executable by your Apache user. At the bottom of the file you'll need to provide the full path to a config file which you'll create in the next step, so that's /var/www/hg.example.com/cgi-bin/hgweb.config . Now create hgweb.config, remembering to chown, and specify the path to your repositories as below.

[paths]
/ = /var/hg/**

On the left is what you'll have to append to http://hg.example.com to access the repository listing, in this case it's simply / . On the right is the filesystem path to the directory containing your repositories. The double asterisk allows recursion into directories that are not themselves repositories, so you can have for example /var/hg/bobs-repos/repo1, /var/hg/bobs-repos/repo2, /var/hg/daves-repos/repo1 et cetera.

Configuring mod_wsgi

There's nothing special to be done as regards server-wide setup for mod_wsgi, so now you can take your favourite template VirtualHost block, and insert the relevant lines as below. I choose to use mod_wsgi's daemon mode, in which each WSGI application runs as a separate process, though embedded mode is also perfectly feasible for this application. The hg.example.com tags in WSGIDaemonProcess and WSGIProcessGroup are merely descriptive and need not be related to the domain name. Again your choice of authentication method, if any, is obviously non-critical.

<VirtualHost *:80>
  ServerName hg.example.com
  DocumentRoot /var/www/hg.example.com/htdocs

  WSGIScriptAlias / /var/www/hg.example.com/cgi-bin/hgwebdir.wsgi
  WSGIDaemonProcess hg.example.com user=apache group=apache processes=2 threads=15
  WSGIProcessGroup hg.example.com

  <Directory /var/www/hg.example.com/cgi-bin>
    AuthType basic
    AuthBasicProvider ldap
    AuthName "Mercurial Repositories"
    AuthLDAPURL ldap://localhost:389/ou=People,dc=example,dc=com?uid?sub?(objectClass=posixAccount)
    Require valid-user

    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>

Configuring repositories

The behaviour of individual repositories is set in /var/hg/reponame/.hg/hgrc . You may control push rights of users either at this point, or in the HTML authentication, using <LimitExcept> if necessary as outlined in the first wiki link.

[web]
name            = reponame
description     = Bob's magic Hg repo
contact         = bob@example.com
# force SSL for pushes
push_ssl        = false
# users who may push (comma separated)
allow_push      = *
# users who may not push
#deny_push      = dave
allow_archive   = gz zip bz2

As for the repository permissions, the wiki recommends giving the Apache group permissions on the directories. Mercurial users are members of the Apache group to facilitate creation of new repositories without recourse to sudo. It would be much more elegant to keep repositories owned by their creator's user and group, and grant Apache permissions on them using extended POSIX access control lists, but that will be the subject of a separate post. Permissions should be set as follows:

chgrp -R apache /var/hg/reponame
chmod -R g+rw /var/hg/reponame
chmod g+x /var/hg/reponame
chmod g+x /var/hg/reponame/.hg

Finished!

After restarting Apache, you should able to point your browser to http://hg.example.com/ and see your repositories listed. Mission accomplished.

Leave a Reply

You must be logged in to post a comment.