Setting up an HTTP-accessed Mercurial repository on shared web hosting (e.g. Dreamhost)

Date: Fri Apr 25 2014 Dreamhost »»»» Mercurial

The goal of my previous two blog entries was to access my mercurial repository via http (to clone the repository) and via ssh (to commit changes into the repository). The next step in my journey was setting up the HTTP access.

It's possible to rent web service for mercurial hosting (see: MercurialHosting) but in my case I'm already renting this dreamhost account and I want to use its oodles of disk space to stash stuff which I can retrieve from "anywhere". FWIW dreamhost offers subversion hosting as one of their "goodies" but after 1+ years using it, well, let's just way I desperately want to use something else.

Mercurial has a built in web server for serving repositories over HTTP but it's impossible to use this on a shared hosting account, and in any case they make it clear the hg serve server is suboptimal.

PublishingRepositories makes it clear how to use the two CGI scripts provided with Mercurial. The first,

hgweb.cgi
</span>, supports only a single repository.  The other, <span class="geshifilter">
hgwebdir.cgi
</span>, supports multiple repositories and is more flexible.  I'm going to use the second one as it's clear (to me) I'll be using multiple repositories.</p><p>In addition to <a href="http://www.selenic.com/mercurial/wiki/index.cgi/PublishingRepositories">PublishingRepositories</a> it's useful to consult <a href="http://www.selenic.com/mercurial/wiki/index.cgi/HgWebDirStepByStep">HgWebDirStepByStep</a>.</p><p>The first step is to create a subdomain and website to house the mercurial repository.  The subdomain could be <span class="geshifilter">
hg.example.com
</span> (mine is housed at <span class="geshifilter">
hg.davidherron.com
</span>).  Most hosting providers have a control panel that lets you create domains, subdomains, websites, etc, and it's here that you set it up.  This requires both the subdomain by which the repository is referred to (<span class="geshifilter">
hg.example.com
</span>) and the webserver configuration to enable HTTP access to the domain.  The Mercurial documentation discusses setting up virtual hosting in an apache <span class="geshifilter">
httpd.conf
</span> file, however with shared hosting the control panel takes care of configuring the virtual hosting for you.</p><p>Your webserver must be configured to allow CGI execution.</p><p>The next step is to retrieve the CGI file.  It is either in the source distribution or you can retrieve it from the Mercurial web site using this URL: <a href="http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi" title="http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi">http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi</a></p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">$ cd docroot<br>$ wget <a href="http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi<br />">http://www.selenic.com/repo/hg-stable/raw-file/tip/hgwebdir.cgi<br></a></pre></div><p></p><p>It's important to put this CGI script in the directory set up to store the files for your chosen subdomain (<span class="geshifilter">
hg.example.com
</span>).  In the hosting provider control panel, when you create the subdomain it will also tell you a pathname on the server's file system corresponding to this subdomain.  It's this directory where you place the <span class="geshifilter">
hgwebdir.cgi
</span> file.</p><p>Again, your webserver must be configured to allow CGI execution.  Additionally it must treat files ending with ".cgi" as a CGI.  This detail will be configured in your hosting provider control panel and, indeed, it may be the default when the domain is configured.</p><p>The next step is to rename the file more appropriately</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">$ mv hgwebdir.cgi index.cgi<br>$ chmod +x index.cgi</pre></div><p></p><p>The name <span class="geshifilter">
index.cgi
</span> is more appropriate and makes more sense in a URL.  It's purely arbitrary of course but that the population out there understands "index.html" and the like as the main URL for a directory.  The CGI script also has to be executable.</p><p>The next step is to tweak the script a little based on your own needs.  A lot will depend on specifics of your web hosting arrangement.</p><p>The first line of the script ensures it is executed by python.  It's essential that this python be the one into which mercurial has been installed.  If you installed a local python and mercurial <a href="http://davidherron.com/blog/topics/648-installing-mercurial-shared-webhosting-account-such-dreamhost">as I did</a> then the script will have to read something like this:-</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">#!/usr/bin/env /home/reikiman/bin/python</pre></div><p></p><p>The path <span class="geshifilter">
/home/reikiman
</span> would be wherever you installed python. </p><p>A couple lines into the script is <span class="geshifilter">
# adjust python path if not a system-wide install:
</span>  If, as I did, your mercurial is not installed in the system-wide python you'll have to take action here as well.  Uncomment the following two lines and edit similarly to this:-</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"># adjust python path if not a system-wide install:<br>import sys<br>sys.path.insert(0, "/home/reikiman/lib/")</pre></div><p></p><p>A few lines further down is a couple lines which allow pages to be encoded with UTF-8.  I believe that's a good idea and have uncommented them in my setup.</p><p>The next step is to create the <span class="geshifilter">
hgweb.config
</span> file.  It's syntax is briefly described in the CGI script and <a href="http://www.selenic.com/mercurial/wiki/index.cgi/HgWebDirStepByStep">HgWebDirStepByStep</a> has more detail.  The initial configuration to put in this file is to initialize the repository (repositories) to serve.</p><p>The file should contain</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">[paths]<br>repo1 = path/to/repo1<br>repo2 = path/to/repo2<br>...</pre></div><p></p><p>It's probably simplest to put the repository right in the docroot such that your config file might read:-</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">[paths]<br>drupalv5 = drupalv5<br>drupalv6 = drupalv6<br>...</pre></div><p></p><p>The left-hand-side of each line is the name mercurial will show for the repository, while the right hand side is the path where mercurial will find the repository.</p><p>With this much set up you should be able to visit, with your browser, <span class="geshifilter">
<a href="http://hg.example.com/path/index.cgi/repo1">http://hg.example.com/path/index.cgi/repo1</a>
</span> and see the repository in your browser.  Additionally you should be able to retrieve the repository this way:-</p><p></p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">$ hg clone <a href="http://hg.example.com/path/index.cgi/repo1<br />">http://hg.example.com/path/index.cgi/repo1<br></a></pre></div><p></p><p>It may be possible to do server config such that the "index.cgi" is not required in the URL.  On <a href="http://www.selenic.com/mercurial/wiki/index.cgi/PublishingRepositories">PublishingRepositories</a> is given a snippet of code that can be used in a .htaccess file, however I just tried this and it did not work.</p><p></p><div class="field field-type-emvideo field-field-extvideo">      <div class="field-label">extvideo:&nbsp;</div>    <div class="field-items">            <div class="field-item odd">                    <div class="emvideo emvideo-video emvideo-"></div>        </div>              <div class="field-item even">                    <div class="emvideo emvideo-video emvideo-"></div>        </div>              <div class="field-item odd">                    <div class="emvideo emvideo-video emvideo-"></div>        </div>              <div class="field-item even">                    <div class="emvideo emvideo-video emvideo-"></div>        </div>        </div></div><!-- google_ad_section_end --><div class="sexybookmarks-default-3452"></div></body></html>