Setting up a Mercurial server under IIS7 on Windows Server 2008 R2

This guide walks you through setting up a Mercurial server under IIS7 on Windows Server 2008 R2.

Note: This post uses Mercurial 1.4.3 and Python 2.5.4, although this process will also work with Mercurial 1.5 and Python 2.6.4

Install Mercurial

First you’ll need to download and install Mercurial. I won’t walk through this as it’s a simple case of pressing "next" several times.

Install Python

Next you’ll need to install Python. Note that you need to use the same version of Python that was used to build Mercurial. This guide uses Mercurial 1.4.3 with Python 2.5.4, but if you’re installing Mercurial 1.5 then you’ll need to use Python 2.6 instead.

Be sure to install the x86 version of Python even if you’re running on an x64 system.

Get hgwebdir

Next you’ll need to download hgwebdir.cgi. This is the python script that will allow serving Mercurial repositories through a web server.

Hgwebdir is part of the Mercurial source code, so you’ll need to download the source package to get it. This can be found on the Mercurial site or you can check out the hg source by running the following command:

hg clone http://selenic.com/repo/hg

Once downloaded, hgwebdir.cgi is in the root of the source distribution.

Install IIS

Under Windows Server 2008 you can install IIS under the Server Manager and clicking "Add Roles". Proceed through the wizard and select the "Web Server (IIS)" role.

Under "Role Services" ensure that you enable Basic Authentication as well as CGI extensibility.

Configure Python for IIS

First, create a new directory under the wwwroot directory (C:inetpubwwwroot). I’m going to call it "hg".

In the "Handler mappings" section for this directory select "Add Script Map":

Next, enter *.cgi as the Request Path and the Executable Path should be set to c:Python25python.exe -u "%s". Enter "Python" as the Name.

At this point, you can test whether Python is working properly by creating a simple python script:

print 'Status: 200 OK'
print 'Content-type: text/html'
print
 
print '<html><head>'
print ''
print '<h1>It works!</h1>'
print ''
print ''

Save this in the directory that you created (C:inetpubwwwroothg) as test.cgi. Now, when you point your browser to http://localhost/hg/test.cgi you should see the following output:

Enabling hgwebdir.cgi

First, copy hgwebdir.cgi (that you downloaded in step 3) and paste it into c:inetpubwwwroothg. Open this file in a text editor and scroll down to the end. The last lines should look like this:

application = hgwebdir('hgweb.config')
wsgicgi.launch(application)

Change the first line to explicitly specify the path to your hg directory:

application = hgwebdir('c:inetpubwwwroothghgweb.config')
wsgicgi.launch(application)

Next, you’ll need to unzip the Mercurial library into c:inetpubwwwroothg. This can be found in Library.zip under the c:program files (x86)Mercurial directory.

You’ll now need to copy the hgweb templates directory into c:inetpubwwwroothg. This is located in the root of the Mercurial installation directory (C:program files (x86)Mercurial)

Finally, create a file called hgweb.config in c:inetpubwwwroothg. This file can be empty for now (we’ll be putting something in it shortly).

At this point, visiting http://localhost/hg/hgwebdir.cgi will show you an empty repository page:

Configuring Repositories

Now you’ll need to create some repositories to publish. To do this, create a directory in the root of the C: drive called "Repositories". This is where our repositories are going to be stored.

Next, I’m going to create a "test" repository by issuing the following commands:

cd c:repositories
mkdir test
hg init test

Now we have a repository created, we need to tell hgwebdir where to find it. We can do this by opening up the hgweb.config file we created earlier and adding the following lines:

[collections]
C:repositories = C:repositories

Now, visiting http://localhost/hg/hgwebdir.cgi should display our "test" repository

At this point it should now be possible to clone the test repository from the server with the following command:

hg clone http://localhost/hg/hgwebdir.cgi/test

Pretty URLs

Personally, I don’t like having to specify "hgwebdir.cgi" in the URLs. I’d much prefer something like http://localhost/hg/test to access my test repository.

This can be achived by using the URL rewriting extension for IIS which can be downloaded from Microsoft.

Once installed, you can access the URL rewriting settings though the "URL Rewrite" section of the IIS Manager. Select the "hg" subdirectory in the Connections pane and then select "URL Rewrite":

In the URL rewrite section add a new blank rule. The name of the rule is going to be "rewrite to hgwebdir".

Under the "Match URL" section set "Using" to "Wildcards" and set the "Pattern" to "*"

Under "Conditions" we want to ensure that we do not re-write URLs to any physical files, so add a condition for "Is Not a File":

In the "Rewrite URL" box at the bottom of the screen enter hgwebdir.cgi/{R:1}

The end result will look like this:

Finally, re-open your hgweb.config and add the following section:

[web]
baseurl = /hg

This will ensure that hgwebdir generates urls to /hg rather than /hg/hgwebdir.cgi

Now, visiting http://localhost/hg will display our repositories page and http://localhost/hg/test will show our test repository. Likewise, we can now clone repositories using this url format.

Pushing Changes

By default, all repositores served via hgwebdir are read only – you cannot push changes to them. To change this, we can specify the users that should be able to push to the repositores by adding an "allow_push" section to our hgweb.config:

[collections]
c:repositories = c:repositories
 
[web]
baseurl = /hg
allow_push = Jeremy

This means that the user account "Jeremy" (a local user account on the server) will have push access to the repository.

However, if we try and push changes we’ll get an error:

c:projectstest&gt;hg push
pushing to http://localhost/hg/hgwebdir.cgi/test
searching for changes
ssl required

For now, we’ll disable SSL by setting push_ssl to false in our hgweb.config:

[collections]
c:repositories = c:repositories
 
[web]
baseurl = /hg
allow_push = Jeremy
push_ssl = false

Now when we try and push we get a different error:

c:projectstest&gt;hg push
pushing to http://localhost/hg/hgwebdir.cgi/test
searching for changes
abort: authorization failed

This happens because by default IIS is serving up our site without authentication. We need to enable Basic Authentication in the Authentication area of IIS:

Now you’ll be prompted to enter your username and password:

After specifying the credetails, the changes will be pushed up. We can view the commit in our web UI:

Enabling SSL

When you use Basic authentication, your username and password will be sent over the wire in plain text. To make this more secure we can enable SSL. For this example I’m going to use a self-signed certificate, although this will also work with a real SSL certificate purchased from a provider.

First, you’ll need to go into the IIS manager, select "Server Certificates" and click "Create Self-Signed Certificate"

Now, add a binding for your Web Site for https on port 443 by right clicking on the site and selecting "Edit Bindings".

Add a new binding for https on port 443:

Once this is done, you should now be able to access the hgwebdir site by using https (https://localhost/hg). You’ll probably get an invalid certificate warning in your browser.

Now you can re-clone the repository using the secure url (also be sure to remove the "push_ssl = false" line from hgweb.config)

All done!

At this point, you should have successfully set up everything you need to use Mercurial in IIS7.