Introduction
I was recently tasked with updating our Mercurial repository at work. The original repository and configuration using Apache had been in place for years without issues generally. The latest Apache versions for Windows are provided by third parties and not from Apache Foundation anymore.
When I looked at the configuration we were using, the Python FastCGI modules were very old and had not been updated in years. In fairness, they didn’t need to be for our application, but there were no updates for the latest Apache HTTPD server. The existing third party versions of Apache didn’t include the required libraries for the old modules. I didn’t want to install everything required to compile a new version of Apache for our environment. This would add application maintenance overhead to me to maintain and update it. So what were my alternatives?
Since the application was already running on a Windows server, I decided to see if I could implement it on Windows without having to migrate to a Linux server. Although migrating to Linux, or UNIX would have been my preference, it was not available to me. The solution was to try to use IIS to serve up the application. Specifically, I had a set of requirements:
- Windows AD authentication.
- Mercurial needed to be available via HTTPS.
- Latest version of Mercurial
- Simple implementation
- Easy maintenance
The ease of maintenance would be normal Windows server updates. The implementation should be sufficiently simple that a new ops, or engineer could be assigned the task of updating it, or maintaining it.
Since Mercurial is popular, I thought finding some details on deploying Mercurial on IIS would be simple. I found some blog posts and wiki pages on it, but they were very old. Nothing was up-to-date. So I decided to write my own post with details I gathered from multiple blog posts and references.
Python
Install Python. I installed the python-2.7.15.amd64.msi on the server accepting the defaults except I also added Python to the path as shown below.
Mercurial
Install Mercurial. I installed mercurial-4.6.1.win-amd64-py2.7.msi which will install it into the Python installation.
Once the installation is complete open a command prompt or Powershell and type hg. It should display a list of commands available.
IIS
Install/activate IIS. We need to insure that CGI is enabled for wfastcgi.
- Open Server Manager
- Go to Add Roles and Features. Scroll down and select Web Server (IIS) and Next. Continue Next until you reach Role Services.
- (OPTIONAL) Under Performance, select Dynamic Content Compression.
- (OPTIONAL) Under Security, select any mechanism you want to use to allow users to connect. I selected Basic Authentication and Windows Authentication. Click Next.
- Check options and click Install.
- Once the install completes, we need to go back to Add Roles and Features. This time navigate to Application Development and select CGI.
Python FastCGI implementation (wfastcgi)
I looked for an implementation that would provide the sufficient capabilities to serve up the pages quickly with little overhead. I looked at a number of implementations. I was looking at wfastcgi and noticed that it was created and maintained by Microsoft. Bonus!
- Using a command prompt or Powershell. type the following:
pip install wfastcgi
- Once pip finshes installing wfastcgi, run the following command to enable wfastcgi.
wfastcgi-enable
- After enabling wfastcgi, we can refresh our IIS Application Server Manager instance and we will have a new IIS management category called FastCGI Settings. Just confirm its presence we will attend to it shortly.
- Next go to Sites in IIS Admin and ensure that you have the Default Website stopped.
- Right-click and Add Website. This will bring up a form to configure. I set my settings as shown below. You may change them to meet your needs.
- Set the website bindings as shown below:
Final Configuration
- Copy the C:\Python27\Lib\site-packages\wfastcgi.py to the root directory of your new site. In my case it is the C:\inetpub\hg directory.
- Place the following script in the root directory and name it hgweb.py:
config = "hgweb.config" from mercurial import demandimport; demandimport.enable() from mercurial.hgweb import hgweb application = hgweb(config)
- Create a hgweb.config file and place it in the root directory. If you use the script below, please make sure you have a path to your repositories set. You can use the instructions available in Mercurial to reconfigure it later. Here is an example:
[web] encoding = UTF-8 allow_push = * push_ssl = False allow_archive = gz zip bz2 descend = True collapse = True style=gitweb [paths] / = C:\repos\*
NOTE: This method of listing repositories can be very slow if there are a number of repositories. It is better to list them individually.
- Go to the IIS Admin Sites and select your Mercurial site. Go to Handler Mappings.
- Click Add Module Mapping and provide the following details:
- Request Path: *
- Module: FastCgiModule
- Executable: C:\Python27\python.exe|C:\inetpub\hg\wfastcgi.py WARNING: There can not be any spaces between the values and the pipe (|) character otherwise it won’t work and you will be hating life trying to figure out why its not working.
- Name: hg-wfastcgi Continue to the next step below.
- Click on Request Restrictions button.
- Mapping » Uncheck checkbox Invoke handler only if request mapped to.
- Verbs: » All Verbs radio button selected.
- Access: » Script radio button selected. Click OK.
- Click OK. This will prompt you to create an application to handle the requests. Important Click *Yes**.
- Configuring wfastcgi to respond to Mercurial requests. Go to the IIS Admin FastCGI Settings page.
- You should see the newly created handler at the bottom of the list. Click Edit which will bring up the form window. If it doesn’t exist, then you will need to Add Application. Fill in the following:
- Full Path: C:\Python27\python.exe (Only required if adding application)
- Arguments: C:\inetpub\hg\wfastcgi.py (Only required if adding application)
- General » Max Instances: 10
- Process Model » Activity Timeout: 300
- Process Model » Idle Timeout: 600
- Process Model » Request Timeout: 600
- General » Environment Variables: You will be adding the following environment variables:
- Name: PYTHONPATH Value: C:\inetpub\hg
- Name: WSGI_HANDLER Value: hgweb.application
- Restart the web server and you should be in business. Open a browser and go to the address of the machine and you should see any repositories that are listed in your hgweb.config file.
Security
The application is not configured with authentication at this point. If you decide to use AD, you will need to configure IIS for the site to use AD. If you choose to use authentication, don’t forget to modify the hgweb.config file to allow_push for the users that should be allowed to push changes to the repository.
References
- Setting up a Mercurial server under IIS7 on Windows Server 2008 R2
- Running Mercurial 2.x Web server on IIS 7.5
- Setting up a Mercurial server under IIS7 on Windows Server 2008 R2
- wfastcgi 3.0.0
- Deploying Python web app (Flask) in Windows Server (IIS) using FastCGI
- 3.2. Getting the hgweb script
- Python Flask on IIS with wfastcgi