I recently ran through the process of setting up a Mercurial server on IIS 7.5. It was a little painful and not something I would recommend, more so now that Bitbucket is offering free unlimited private repositories for teams with five developers (if Bitbucket isn't your cup of tea, you can find more Mercurial hosters here). If however your client isn't comfortable with having source code hosted externally, you may want to get yourself a Linux/Apache box and follow this comprehensive guide. If you can't do that either, and really want to use IIS 7.5 on Windows 2008 R2, then keep reading (and keep the Advil handy).
This is based on the guide Jeremy Skinner provides on his blog. A few things have changed in Mercurial since it was written however, which prompted me to document exactly what I did differently, and for the sake of completeness, document what I did the same.
These aren't requirements so much as just what I used. Later versions may work the same way (although they didn't for Jeremy's guide).
Mercurial is based on Python, and it seems to matter which version of Python is installed. To find out which version of Python Mercurial needs, install TortoiseHg either on the server or the client (or both) and have a look at the About TortoiseHg screen. This version of Mercurial uses Python 2.6.4, but I could only find Python 2.6.6. However, I think as long as the major and minor version numbers match, everything should be fine.
I'm installing Mercurial the Python package, not Mercurial the stand-alone program. Make sure you grab the right one. Mercurial as a Python package means Python can find it easily. I also grabbed the 32 bit version of Python and Mercurial just to get this working as soon as possible. Things may work with the 64 bit versions, but it wasn't something I was willing to fiddle with. If you're feeling brave you might want to give it a go.
TortoiseHg is completely optional on your server. I installed it so I can browse my repositories with it while I'm logged into the server, but if you hardly ever RDP into your server you won't need it. It can be handy to init new repos with it, but that can be accomplished using your local machine and a network share.
If your Windows Server doesn't already have IIS 7.5 installed, go ahead and do that now using Server Manager. Make sure CGI and Basic Authentication are installed. (Ignore the other items have checked, they're for other applications.)
Install Python 2.6. It's pretty straight forward and it will end up in a directory like C:\Python26
by default. Once that is complete, install the Mercurial Python package. This will look for Python and install itself in the C:\Python26\Lib\site-packages
directory.
This part of the process is very similar to Jeremy's guide, so I will go over this quickly. If you need more details, Jeremy's effort may have them.
Create an application under the default web site and call it whatever you like, I called it hg
like Jeremy did. The physical location is C:\inetpub\wwwroot\hg
.
Next, go into Handler Mappings and add a Script Map for CGI. Enter *.cgi
for the request path, C:\Python26\python.exe -u "%s"
for the executable, and Python
for the name.
To test this works, create a simple Python script and save it in the application directory as test.cgi
.
print 'Status: 200 OK'
print 'Content-Type: text/html'
print
print '<html><body><h1>It Works!</h1></body></html>'
Browse to http://localhost/hg/test.cgi to see if it works.
The next thing to do is get a hold of hgweb.cgi
, which isn't included in any of the Mercurial installations that were just performed as far as I can tell. One way to grab it is to browse the Mercurial source code here and download it, or you can cut and paste the following and save it to C:\inetpub\wwwroot\hg\hgweb.cgi
.
#!/usr/bin/env python
#
# An example hgweb CGI script, edit as necessary
# See also http://mercurial.selenic.com/wiki/PublishingRepositories
# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "/inetpub/wwwroot/hg/hgweb.config"
# Uncomment and adjust if Mercurial is not installed system-wide:
#import sys; sys.path.insert(0, "/path/to/python/lib")
# Uncomment to send python tracebacks to the browser if an error occurs:
#import cgitb; cgitb.enable()
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb import hgweb, wsgicgi
application = hgweb(config)
wsgicgi.launch(application)
This differs from Jeremy's guide because hgwebdir.cgi
and hgweb.cgi
were combined in Mercurial 1.6. The hgweb.cgi
file now handles both single and multiple repositories.
If you've downloaded the file, open it up and change line 7 to match line 7 above. This is the location of the Mercurial configuration file.
Next, create an empty file and call it hgweb.config
. More information will go into it later -- right now an empty file equates to default settings. At this point there should be four files in the C:\inetpub\wwwroot\hg
directory.
That's enough to get Mercurial running. There's no need to copy the Mercurial library or template directory locally, that's what the Mercurial Python package was for. Browse to http://localhost/hg/hgweb.cgi and the following should be displayed.
Jeremy had a great suggestion at this point to create a rewrite rule to eliminate hgweb.cgi
from the URL. To do this, URL Rewrite must be added to IIS 7.5 first. The easiest way to do that is to install Web Platform Installer and then install URL Rewrite 2.0 through that.
Now you can follow Jeremy's guide to create the rewrite rule via the interface, or you can cut and paste the <rewrite>
section below into your web.config
file, just after </handlers>
.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="Python" path="*.cgi" verb="*" modules="CgiModule" scriptProcessor="C:\Python26\python.exe -u "%s"" resourceType="Unspecified" requireAccess="Script" />
</handlers>
<rewrite>
<rules>
<clear />
<rule name="hgweb.cgi" enabled="true" patternSyntax="Wildcard">
<match url="*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="hgweb.cgi/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Next, edit the hgweb.config
file to let Mercurial know how URLs should be generated.
[web]
baseurl = /hg
Browse to http://localhost/hg to see the same screen as before.
Now to choose a location for the Mercurial repositories. I went with C:\Repositories\Hg
. To tell Mercurial about the location, open hgweb.config
and modify it like so...
[collections]
/Repositories/Hg = /Repositories/Hg
[web]
baseurl = /hg
Create a new repo, Test, in the directory and refresh the browser.
You may encounter permission errors when browsing now or later on after some changesets have been pushed. If you do, grant the local IIS_IUSR
group permission to read the C:\Repositories\Hg
directory.
The Test repository should be clonable, but pushing should fail. Over on a client machine, run some quick checks.
All pushes require SSL, lest credentials be transmitted in the clear. For now we'll disable SSL by adding another line to hgweb.config
.
[collections]
/Repositories/Hg = /Repositories/Hg
[web]
baseurl = /hg
push_ssl = false
Now the push should fail on authorisation.
Modify hgweb.config
again to let everyone push.
[collections]
/Repositories/Hg = /Repositories/Hg
[web]
allow_push = *
baseurl = /hg
push_ssl = false
Try the push again, this time it should work.
Refreshing the browser will show the test commit.
Letting everyone push probably isn't a great idea. This is remedied by turning on authentication in IIS and telling Mercurial to authorise. To get started, go back to IIS Manager and enable Basic Authentication. Setting the default domain and realm can also be handy.
Now edit the hgweb.config
file to limit who can push.
[collections]
/Repositories/Hg = /Repositories/Hg
[web]
allow_push = Adam.Boddington
baseurl = /hg
push_ssl = false
Pushing another test will result in Mercurial asking for a username and password, authenticated against the domain.
If you get bad gateway errors here the pusher may not have write permissions on the directory. You may want to try giving all pushers write permissions on C:\Repositories\Hg
. Alternatively, a local group on the server for pushers which has the required permissions may make life easier.
Passing credentials around in the clear, even on a corporate LAN, is never a good idea. Luckily setting up SSL isn't difficult. First, create a self-signed certificate on the server (or use a real certificate if you have one).
Go into the bindings for the default web site.
Add a new HTTPS binding using the self-signed certificate.
Turn SSL back on for Mercurial by removing the push_ssl = false
line from the hgweb.config
file.
[collections]
/Repositories/Hg = /Repositories/Hg
[web]
allow_push = Adam.Boddington
baseurl = /hg
New in Mercurial 1.7.3 is the automatic checking of certificates against Certification Authorities (CAs). This is a slight problem for self-signed certificates -- the check will always fail. Luckily in Mercurial 1.7.5 there is the ability to skip the check by adding an --insecure
option to the command.
To avoid having to type --insecure
with every command there are two ways to tell Mercurial to trust the self-signed certificate. The first is to export the certificate in X.509 PEM format and append it to the cacert.pem
file in each client's TortoiseHg program files folder. (Firefox can export the certificate and gvim can edit the cacert.pem
file.) The second much easier way is to simply add the "fingerprint" of the server to each client's Mercurial global settings (mercurial.ini
). If you're using a build server running under a system account that doesn't have a user profile, the fingerprint can be added to the mercurial.ini
file in the TortoiseHg program files folder (the mercurial.ini
file may have to be created).
[hostfingerprints]
enebrisabs01 = c0:86:63:78:44:6f:f4:62:a4:b3:92:30:c1:3e:e9:71:53:6e:0a:ce
The fingerprint is displayed by Mercurial when using the --insecure
option.
I haven't tried this yet myself, but if permission is required on a repo by repo basis, try setting up .NET authorisation on each repo folder. It should be possible to set up allow/deny rules on any folder that requires it.
There are 8 comments.
browse with Pivot
Codility Nitrogenium Challenge
OS X Lock
HACT '13
Codility Challenges
Priority Queue
Architecture (13)
ASP.NET (2)
ASP.NET MVC (13)
Brisbane Flood (1)
Building Neno (38)
C# (4)
Challenges (3)
Collections (1)
Communicator (1)
Concurrency Control (2)
Configuration (1)
CSS (5)
DataAnnotations (2)
Database (1)
DotNetOpenAuth (2)
Entity Framework (1)
FluentNHibernate (2)
Inversion of Control (5)
JavaScript (1)
jQuery (4)
Kata (2)
Linq (7)
Markdown (4)
Mercurial (5)
NHibernate (20)
Ninject (2)
OpenID (3)
OS X (1)
Pivot (6)
PowerShell (8)
Prettify (2)
RSS (1)
Spring (3)
SQL Server (5)
T-SQL (2)
Validation (2)
Vim (1)
Visual Studio (2)
Windows Forms (3)
Windows Service (1)
Comments
Nick wrote on Wednesday, 6 April, 2011 @ 4:33 AM
This was an excellent post, It was very well put together. I actually tried these instructions on a 64bit windows 7 system and pretty much everything worked. The only problem was Python, I had to get the 64bit download, called "mercurial-1.8.1.win-amd64-py2.6.exe", try to get the .exe and not the .msi. For some reason I think the .msi doesn't register python 2.6.6. into the Windows 7 registry. Other then that everything works on 1.8.1. mercurial.
Thanks a bunch, Nick
Ali T wrote on Sunday, 8 May, 2011 @ 1:12 AM
Adam, Thanks a lot for putting this together... :) one of the statements/step above have left me little bewildered though - "•web.config (created automatically to contain the CGI handler mapping)" i am not sure where that(web.config) came from?
right now i am left to stare at the following error! Would greatly appreciate any sort of help :)
Thanks in advance.
Nick Ciereck wrote on Tuesday, 10 May, 2011 @ 4:00 AM
what is the error your getting?
Ive set up this same mercurial server like 4 times, and everytime some little error pops up that I didn't get the other times...Really frustrating! The first two times I set up the Mercurial server, the "web.config" WAS automatically generated, The last two times I had to Manually make & insert the proper code.
Adam Boddington wrote on Thursday, 12 May, 2011 @ 1:21 PM
Ali, IIS Manager creates
web.config
automatically when you create the CGI handler mapping. You can find that step in the section titled Web Application. Would you be able to post the error you're getting?derbjoerm wrote on Thursday, 17 November, 2011 @ 12:11 AM
Hey first of all thx a lot....this is f...... brilliant!
But I have a little problem with the whole Auth&Co. + Push
So everytime i try to HG Push on the PowerShell i get: abort: "repository default-push not found". Everything from the beginning until^works fine, but now...:(
I also searched for a solution, but didnt find anything! I appreciate your help/hint/....! Pls can anyone help me?
thx a lot
Bjoern
JamisonWhite wrote on Saturday, 10 December, 2011 @ 6:22 AM
Adam, great update to Jeremy's article! Have you tried getting Mercurial 2.0's extension working with IIS7?
jed3d wrote on Sunday, 11 March, 2012 @ 4:19 PM
Thanks for a great post! I got it working with Windows 7 Pro with 64-bit versions of everything and even .NET Auth. See my article here http://jediscode.blogspot.com/2012/03/securely-running-64-bit-mercurial.html
Anton Gogolev wrote on Monday, 17 June, 2013 @ 8:40 PM
Or else you can install HgLab and be up an running (and integrated with ActiveDirectory) in a couple minutes. Plus you'll get pushlog, fancy graphs and code analysis tools.
Leave a Comment
Please register or login to leave a comment.