Edgewall Software

IIS configuration for Trac 1.0x and IIS 7.5 (Windows server 2012 and Windows 8)

what you get

Trac using WSGI interface hosted by Microsoft IIS using FastCGI handler.

Static content served by IIS rather than through Trac.

Windows Authentication, if you want it, done by IIS, but authorization managed via Permissions in Trac. No need for AccountManagerPlugin.

What You Need

Windows Server 2012 or Windows 8 Professional with IIS 7.5 installed.

The URL Rewrite extension for your version of IIS.

wfastcgi.py from the Python Tools for Visual Studio project. This is the indispensible glue, all props to the PTVS folks for providing it. It can be downloaded from the releases page.


Probably works for IIS 7.0 or IIS Express (free!) on Windows Server 2008 R2 or Windows 7, but I have not tested it, and won't be doing so.

I have not tried to generalize for collection of Trac environments under a common parent.

This configuration only allows 1 Trac site (environment or parent) per IIS server, because the FastCGI application is defined at the server level and is identified by executable + arguments. To support multiple Trac virtual directories (on default or additional websites, doesn't matter), you might be able to clone wFastCgi.py with different names and different hardcoded environment variable settings, or hack it to accept environment variable definitions from the command line. Either way, you could then define multiple FastCGI applications with different command line arguments and they would be distinguishable by IIS.

What Goes Where

<virtualenv> (in examples below, N:\vePython\trac27)
contains Python interpreter, Trac and plugins. As the name implies, I used a python virtual environment rather than the main install. I don't think it matters.
<tracVDir> (C:\inetpub\wwwroot\tracWSGI)
the physical path to an IIS virtual directory, e.g c:\inetpub\wwwroot\trac. Contains the static content for your Trac environments. This does not need to be a separate site or a .net application under IIS, just a virtual directory.
Trac environment somewhere not under IIS.
Not a requirement, but how I happened to have Trac already running.
<tracURL> (http://localhost/tracWSGI)
The URL of the Trac environment.

Configuration Steps

(I apologize for using the IIS command line here. It is concise and unambiguous, but finickey. But trying to describe gestures in the GUI would be even worse.)

Install CGI and FastCGI handler in IIS:

c:\> start /w pkgmgr /iu:IIS-WebServerRole;IIS-WebServer;IIS-CommonHttpFeatures;IIS-StaticContent;IIS-DefaultDocument;IIS-DirectoryBrowsing;IIS-HttpErrors;IIS-HealthAndDiagnostics;IIS-HttpLogging;IIS-LoggingLibraries;IIS-RequestMonitor;IIS-Security;IIS-RequestFiltering;IIS-HttpCompressionStatic;IIS-WebServerManagementTools;IIS-ManagementConsole;WAS-WindowsActivationService;WAS-ProcessModel;WAS-NetFxEnvironment;WAS-ConfigurationAPI;IIS-CGI

See here for GUI.

Download and install URL Rewrite extension

From here.

Rules get configured below

Deploy static content from Trac into IIS:

trac-admin <tracEnv> deploy <tracVDir>

Configure the FastCGI application at the IIS server root.

Note that IIS only supports one FastCGI application with a given executable and command line. So you're limited to a single Trac environment per IIS server unless you get creative with wFastCgi.py.

FastCGI application invokes Python interpreter (from <virtualenv>) running wfastcgi.py as the argument. wfastcgi.py needs 3 or 4 environment variables.

c:\> appcmd.exe set config -section:system.webServer/fastCgi ^
         /+"fullPath='`<virtualenv>` N:\vePython\trac27\Scripts\python.exe', arguments='n:\vePython\trac27\scripts\wfastcgi.py'"
c:\>appcmd.exe set config -section:system.webServer/fastCgi ^
         /+"[fullPath='N:\vePython\trac27\Scripts\python.exe'].environmentVariables.[name='TRAC_ENV_PATH', value='n:\tracenv\tracWSGI']" /commit:apphost
c:\>appcmd.exe set config -section:system.webServer/fastCgi ^
         /+"[fullPath='N:\vePython\trac27\Scripts\python.exe'].environmentVariables.[name='PYTHON_EGG_CACHE', value='n:\tracenv\tracWSGI.egg-cache']" /commit:apphost
c:\>appcmd.exe set config -section:system.webServer/fastCgi ^
         /+"[fullPath='N:\vePython\trac27\Scripts\python.exe'].environmentVariables.[name='WSGI_HANDLER', value='trac.web.main.dispatch_request']" /commit:apphost

Configure the Handler Map in the Trac virtual directory to invoke the FastCGI application

c:\> appcmd.exe set config "Default Web Service/tracWSGI" -section:system.webServer/handlers ^
          /+"name='Python_FastCGI_WSGI', path='*', verb='*', modules='FastCgiModule', scriptProcessor='n:\vePython\trac27\scripts\python.exe|n:\vePython\trac27\scripts\wfastcgi.py', resourceType='Unspecified', requireAccess='Script'"

The ResourceType=Unspecified is key: otherwise IIS insists that the URI match a file in <tracVdir> before invoking the handler.

Add rewrite rule(s)

These rewrite chrome/common/... and chrome/site/... to htdocs/common/... and htdocs/site/..., respectively.

c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules ^
         /+"[name='siteToHtdocs',stopProcessing='True']" /commit:apphost
c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules ^
         /[name='siteToHtdocs',stopProcessing='True'].match.url:"chrome/site/(.*)"  /commit:apphost
c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules /[name='siteToHtdocs',stopProcessing='True'].action.type:"Rewrite" ^
         /[name='siteToHtdocs',stopProcessing='True'].action.url:"htdocs/site/{R:1}" ^
         /[name='siteToHtdocs',stopProcessing='True'].action.logRewrittenUrl:"True"  /commit:apphost

c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules ^
         /+"[name='commonToHtdocs',stopProcessing='True']" /commit:apphost
c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules ^
         /[name='commonToHtdocs',stopProcessing='True'].match.url:"chrome/common/(.*)"  /commit:apphost
c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/rewrite/rules /[name='commonToHtdocs',stopProcessing='True'].action.type:"Rewrite" ^
         /[name='commonToHtdocs',stopProcessing='True'].action.url:"htdocs/common/{R:1}" ^
         /[name='commonToHtdocs',stopProcessing='True'].action.logRewrittenUrl:"True"  /commit:apphost

There is some magic here: we configure the FastCGI handler to handle *all* URIs under the virtual directory, but also tell rewrite to edit URIs under <vdir>/chrome. Somehow, IIS understands that the rewritten URI should not be passed to FastCGI. But why?

What if magic does not work?

Sometimes the method to isolate static content from Trac described above does not work. The files the htdocs folder are ignored and the css/js files are returned through the FastCGI handler.

If you run into this problem, try the alternative approach:

  • Instead of configuring the URL rewriting rules, create a Virtual Directory called chrome in the root of the website. If you already created URL rewriting rules, remove or disable them.
  • Disable our handler for this virtual directory (through GUI or by modifying web.config as described below).
  • If it returns error 401, make sure that the IUSR account has read permissions for the htdocs folder.

To turn off our handler, find its name in the Handler Modules section of GUI and then create the following web.config file in the root of the htdocs:

<?xml version="1.0" encoding="UTF-8"?>
	    <!-- Use GUI to find out how exactly your FastCGI handler is called -->
            <remove name="Python FastCGI_WSGI" />

If you want to re-enable the FastCGI handler for a specific subfolder of htdocs, you can create a similar web.config in this folder and instead of <remove> tag, insert something like this:

<add name="Python FastCGI_WSGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="[path to python]\python.exe|[path to wfastcgi.py]\wfastcgi.py" resourceType="Unspecified" />

You can also find it in the web.config of the root folder of the site.

Enable Windows authentication, disable anonymous (if you aren't using AccountManagerPlugin)

Trac receives the authenticated user name and greets him/her as a logged in user.

c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/security/authentication/anonymousAuthentication /enabled:"False"  /commit:apphost
c:\> appcmd.exe set config "Default Web Site/tracWSGI" -section:system.webServer/security/authentication/windowsAuthentication /enabled:"True"  /commit:apphost
Last modified 8 years ago Last modified on Nov 26, 2015, 6:13:49 AM
Note: See TracWiki for help on using the wiki.