= Running Trac on IIS 6 using Isapi-wsgi = Contributed by:[[br]] Seb Patane I did this with: * Windows Server 2003 SP2 * Python 2.7 * IIS 6 * Trac 0.12 It may work for other versions. ------------------------------- Jeremy Mattke, Minneapolis, USA. I was able to do this with: * Windows 8.1 * Python 2.7 * IIS 8.5 * Trac 1.0 ------------------------------ I also haven't tested standard authentication as I use the [http://trac-hacks.org/wiki/AccountManagerPlugin AccountManagerPlugin]. I also found this to be significantly faster than the TracOnWindowsIisAjp. The only downside is that whenever a plugin is manually installed/code is changed a full `iisreset` needs to be done to reload the ISAPI dll. Restarting the IIS Site alone doesn't seem to be enough. 1. Download & install the latest [http://code.google.com/p/isapi-wsgi/ Isapi-wsgi] (I used 0.4.2 exe), depends on [http://sourceforge.net/projects/pywin32/files/pywin32 pywin32] (I used Build 216 exe) 1. Generate a `trac.wsgi` script using `trac-admin deploy ` (see TracInstall#cgi-bin) 1. copy `trac.wsgi` into a new file called `trac_wsgi.py` for Isapi-wsgi. Replace the dot with the underscore! 1. Append these extra bits so Isapi-wsgi can generate an ISAPI DLL: {{{ #!C:\Python27\python.exe import isapi_wsgi # The entry points for the ISAPI extension. def __ExtensionFactory__(): # can also be isapi_wsgi.ISAPISimpleHandler return isapi_wsgi.ISAPIThreadPoolHandler(application) if __name__=='__main__': # If run from the command-line, install ourselves. from isapi.install import * params = ISAPIParameters() # Setup the virtual directories - this is a list of directories our # extension uses - in this case only 1. # Each extension has a "script map" - this is the mapping of ISAPI # extensions. sm = [ ScriptMapParams(Extension="*", Flags=0) ] # To serve from root, just set Name="/" vd = VirtualDirParameters(Name="/trac", Description = "ISAPI-WSGI Trac", ScriptMaps = sm, ScriptMapUpdate = "replace" ) params.VirtualDirs = [vd] HandleCommandLine(params) }}} 1. Ensure everything has the right Permissions for the IIS Site user. * READ/EXECUTE: imports from site-packages (including eggs), generated ISAPI dll, trac directory & subdirectories * WRITE/MODIFY: trac/conf/trac.ini, trac/log directory, trac/plugins directory, trac/attachments directory (?), trac/db directory (?), .htpasswd file (if using Account Manager) 1. Generate and Install the ISAPI dll using `python trac_wsgi.py install [--server=]`. Don't forget to do an `iisreset` whenever the filter is reinstalled. * This will automatically create the Virtual Directory, install the ISAPI filter and allow it in Web Service Extensions 1. That's it, everything should work! NOTE: if you have a problem with trac.web.main being found you need to unzip your eggs in the python/lib/site-packages directory for Trac, Genshi and setuptools If there are problems you can enable debugging by inserting the following at the top of `trac_wsgi.py`, reinstalling the ISAPI dll and running `python -m win32traceutil` (will also display TracLogging to `stderr`). {{{ #!C:\Python27\python.exe import sys if hasattr(sys, "isapidllhandle"): import win32traceutil }}} TracModWSGI is probably a good starting point as well, even though it deals with Apache. == Broken Authentication == I had a problem with the [http://trac-hacks.org/wiki/AccountManagerPlugin AccountManagerPlugin] always returning `Invalid Username or Password`. This is because the `REMOTE_USER` environment variable is set (I'm not sure why, since it seems to be empty). In any event, putting `del environ['REMOTE_USER']` in `trac_wsgi.py` solved the problem. == Appendix A - My working trac_wsgi.py (with useful extras) == {{{ #!C:\Python27\python.exe # -*- coding: utf-8 -*- # # Copyright (C)2008-2009 Edgewall Software # Copyright (C) 2008 Noah Kantrowitz # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at http://trac.edgewall.org/wiki/TracLicense. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://trac.edgewall.org/log/. # # Author: Noah Kantrowitz # # IMPORTANT: when you make changes to this file you need to # update the ISAPI filter with the following commands - # C:\Inetpub\trac\cgi-bin> python trac_wsgi.py install --server=Trac # C:\Inetpub\trac\cgi-bin> iisreset # import os """ # Uncommenting this enables debug output # you can see it by opening up a command prompt and executing # > python -m win32traceutil import sys if hasattr(sys, "isapidllhandle"): import win32traceutil """ def application(environ, start_request): if not 'trac.env_parent_dir' in environ: environ.setdefault('trac.env_path', 'C:\\Inetpub\\trac') if 'PYTHON_EGG_CACHE' in environ: os.environ['PYTHON_EGG_CACHE'] = environ['PYTHON_EGG_CACHE'] elif 'trac.env_path' in environ: os.environ['PYTHON_EGG_CACHE'] = \ os.path.join(environ['trac.env_path'], '.egg-cache') elif 'trac.env_parent_dir' in environ: os.environ['PYTHON_EGG_CACHE'] = \ os.path.join(environ['trac.env_parent_dir'], '.egg-cache') # Required for Account Manager logins to work del environ['REMOTE_USER'] from trac.web.main import dispatch_request return dispatch_request(environ, start_request) """ # Uncommenting this enables middleware profiling at /__profile__ # Requires the repoze.profiler egg to be installed from repoze.profile.profiler import AccumulatingProfileMiddleware application = AccumulatingProfileMiddleware(application, log_filename='C:\\repoze.log', discard_first_request=True, flush_at_shutdown=True, path='/__profile__') """ import isapi_wsgi # The entry points for the ISAPI extension. def __ExtensionFactory__(): return isapi_wsgi.ISAPIThreadPoolHandler(application) if __name__=='__main__': # If run from the command-line, install ourselves. from isapi.install import * params = ISAPIParameters() # Setup the virtual directories - this is a list of directories our # extension uses - in this case only 1. # Each extension has a "script map" - this is the mapping of ISAPI # extensions. sm = [ ScriptMapParams(Extension="*", Flags=0) ] # To serve from root, just set Name="/" vd = VirtualDirParameters(Name="/trac", Description = "ISAPI-WSGI Trac", ScriptMaps = sm, ScriptMapUpdate = "replace" ) params.VirtualDirs = [vd] HandleCommandLine(params) }}}