Run Python (Django) websites in IIS

I got into a scenario where it was required to run a Python (Django) website in IIS and, as an additional requirement, the configuration needed to be fully automated. I made a little index with all the steps that I took to make the scenario happen.

  1. Install Python
  2. Install Microsoft IIS with required extra features
  3. Configure IIS so it can make use of Python
  4. Prepare your Python website
  5. web.config for Python
  6. Used resources / other reading material

Install Python
First we need to install Python. In my case, installing it through Chocolatey was a viable option, but any form of installation will work. You can use either Chocolatey, the unattended installer, PowerShell DSC or do it by hand. I had access to Chocolatey, so installing was a one-liner. To keep the log files clean, we added the no-progress trigger.

choco install python --version=3.8.9

Install Microsoft IIS with required extra features
Python requires the CGI feature of IIS. With another fancy PowerShell one-liner we can install IIS, CGI and the management tools all at once.

Install-WindowsFeature -Name Web-Server, Web-CGI -IncludeManagementTools

Configure IIS so it can make use of Python

Now it is time to configure IIS. Python requires a Handler Mapping and the configuration of FastCGI. First we check if the Handler mapping already exists. It will be added if it does not.

[string]$PyPath = "C:\python38\python.exe"
[string]$PyArguments = "C:\python38\lib\site-packages\"

#Add IIS WebHandler
Write-Host "`nGetting Web Handler settings ..."
If ($Null -ne (Get-WebHandler -Name "PythonHandler")) {
    Write-Host "Python Webhandler already configured"
Else {
    Write-Host "Adding Python Webhandler to IIS Handlers mappings"
    add-webconfiguration 'system.webServer/handlers' -Value @{
        Name            = "PythonHandler";
        Modules         = "FastCgiModule";
        ScriptProcessor = "$PyPath|$PyArguments";
        Path            = "*";
        Verb            = "*";
        RequiredAccess  = "Script";

You can verify the handler mapping by starting Internet Information Service Manager (inetmgr.exe) –> open the Handler Mappings module on the root page.

The next step is to configure FastCGI. Again, we first check if the configuration is already set, if it is not, we then do the configuration.

[string]$PyPath = "C:\python38\python.exe"
[string]$PyArguments = "C:\python38\lib\site-packages\"

#Get FastCGI settings
Write-Host "`nGetting FastCGI configuration."
$FastCGIConfig = get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST'  -filter "system.webServer/fastCgi" -Name "." -Recurse | Select-Object -ExpandProperty collection | Select-Object fullpath, arguments

#Set FastCGI settings if they are missing
If (($FastCGIConfig.fullpath -eq $PyPath) -and ($FastCGIConfig.arguments -eq $PyArguments)) {
    Write-Host "FastCCGI config already set"
Else {
    Write-Host "Settings FastCGI config settings"
    Write-Verbose "FullPath: $PyPath" -Verbose
    Write-Verbose "Arguments: $PyArguments" -Verbose
    ADD-WebConfigurationProperty `
        -pspath 'MACHINE/WEBROOT/APPHOST'  `
        -filter "system.webServer/fastCgi" `
        -name "." `
        -value @{fullPath = "$PyPath"; arguments = "$PyArguments" }

We can verify it in the IIS manager by selecting the root –> FastCGI settings.

Prepare your Python website
First we need to install Django and wFastCGI module for Python. After that we will setup our Python project.

$Location = "E:\website"
New-Item $Location -ItemType Directory
Set-Location $Location

pip install django
pip install wfastcgi
django-admin startproject mysite
python "mysite\" runserver

This should get the following result: (ignore the pip warnings please :-))

Now that we have verified that our Python code is working, it is time to use IIS the webserver.

Web.config for Python
Django needs a certain set of environment variables to function. All keys that are located in <appsettings> are converted to session environment variables by IIS. The keys that are shown in this web.config are all required to run Django.

<?xml version="1.0" encoding="utf-8"?>
        <!-- Required Python settings -->
        <add key="PYTHONPATH" value="E:\website\Mysite" />
        <add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()" />
        <add key="DJANGO_SETTINGS_MODULE" value="mysite.settings" />

Place the web.config in the pyton project. In my case that would be E:\website\mysite\web.config.
All we have to do now is add the website to IIS and we are good to go!

Import-Module WebAdministration
New-Website -Name mysite -PhysicalPath E:\website\Mysite -Port 81

And there we have it! A Python Django website running on IIS.

Used resources / other reading material
Django Docs: Writing your first Django app, part 1
Microsoft Docs: Configure Python web apps for IIS
Microsoft Docs: web.config file