Django On IIS
The aim of this article is to deploy Django application on Internet Information Services (IIS).
I am no Django nor Python expert. I had to spend a bit of time reading about Django in order for this to work with IIS. If you are well-versed in these technologies, then I guess there are some tweaks you could make, and app will still run.
There are two ways in which we can deploy Django on IIS:
- HttpPlatform handler
- FastCGI Handler (WFastCGI)
Microsoft recommends using HttpPlatform handler, as wFastCGI is no longer maintained.
I will show you how to setup Django with both HttpPlatform handler and WFastCGI. First, I will do all required things that, regardless of how we set it up in IIS, we need to do.
As for my environment, this is a brand-new Windows Server 2019 VM.
- Install Python & Django
pip install Django==4.1.7
Check python and Django installation:
# Python
python--version
# Django
py -m django --version
C:\Users\azureuser>python --version
Python 3.11.2
C:\Users\azureuser>py -m django --version
4.1.7
Up to this point we have python and Django installed.
We now need the actual application!
Again, not an expert on Django, So I will follow this documentation to create a basic Django application.
Writing your first Django app, part 1 | Django documentation | Django (djangoproject.com)
I will create this application under “C:\sites\site01”
Let us familiarize ourselves with the basic structure:
- The outer
mysite/
root directory is a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like. manage.py
: A command-line utility that lets you interact with this Django project in various ways. You can read all the details aboutmanage.py
in django-admin and manage.py.- The inner
mysite/
directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g.mysite.urls
). mysite/__init__.py
: An empty file that tells Python that this directory should be considered a Python package. If you’re a Python beginner, read more about packages in the official Python docs.mysite/settings.py
: Settings/configuration for this Django project. Django settings will tell you all about how settings work.mysite/urls.py
: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in URL dispatcher.mysite/asgi.py
: An entry-point for ASGI-compatible web servers to serve your project. See How to deploy with ASGI for more details.mysite/wsgi.py
: An entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.
Start manage.py. This will run under “http://localhost:8000”. Although you can specify the port.
py manage.py runserver
If all goes well, you should have three routes:
The “Not Found” route:
/polls:
/admin:
Great, now we have our Django application working. Well, not completely, but this will suffice for our tutorial.
The only thing that I will add to the current folder structure is that I am going to create a folder called “logs” for later use.
This is my folder structure for “C:\sites\site01”:
C:\sites\site01>tree /F
C:.
└───mysite
│ db.sqlite3
│ manage.py
│
├───logs
├───mysite
│ │ asgi.py
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
│ │ __init__.py
│ │
│ └───__pycache__
│ settings.cpython-311.pyc
│ urls.cpython-311.pyc
│ wsgi.cpython-311.pyc
│ __init__.cpython-311.pyc
│
└───polls
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ urls.py
│ views.py
│ __init__.py
│
├───migrations
│ __init__.py
│
└───__pycache__
urls.cpython-311.pyc
views.cpython-311.pyc
__init__.cpython-311.pyc
Now I want to make two Django Apps, one will be using HttpPlatform and the other one will be using WFastCGI.
Made a copy of “C:\sites\site01” and renamed it as “C:\sites\site02”.
Like so:
C:\sites>tree
C:.
├───site01
│ └───mysite
│ ├───logs
│ ├───mysite
│ │ └───__pycache__
│ └───polls
│ ├───migrations
│ └───__pycache__
└───site02
└───mysite
├───logs
├───mysite
│ └───__pycache__
└───polls
├───migrations
└───__pycache__
C:\
IIS
Both methods require IIS. Default installation through Server Manager is fine.
With PS:
Install-WindowsFeature -name Web-Server -IncludeManagementTools
For both methods we need to edit come Handler Mappings. However, by default, this has only read permissions. We need to have Read/Write.
IIS Manager > Server Level > Feature Delegation > Handler Mappings > Read/Write
Option 1 — HttpPlatform Handler
I will create a new website called “site01” accessible under “http://localhost:8001”.
The HttpPlatformHandler v1.2 is an IIS Module which enables process management of HTTP Listeners and proxies requests to the process it manages.
The HttpPlatformHandler v1.2 is an IIS module which does two things:
- Process management of HTTP Listeners — this could be any process that can listen on a port for HTTP requests, for example Tomcat, Jetty, Node.exe, Ruby etc.
- Proxy requests to the process it manages.
Configure httpPlatform
IIS Manager > Sites > Site01 > Configuration Editor > system.webServer/httpPlatform
- Arguments: path where “manage.py” is. Run it with “manage.py runserver %HTTP_PLATFORM_PORT%”
- environmentVariables: an environment variable that will dynamically pass the value of the server variable “SERVER_PORT” into. %HTTP_PLATFORM_PORT%
- processPath: path where “python.exe” is.
- stdoutLogEnabled: True
- stdoutLogFile: path where logs will be stored.
Now, Django needs some specific path settings:
- PYTHONPATH: path to where you app is. In my case is pointing to mysite<OUTER>
- WSGI_HANDLER: django.core.wsgi.get_wsgi_application()
- DJANGO_SETTINGS_MODULE: path where “settings.py” is. Thanks to PYTHONPATH we just need to access “mysite<INNER>.settings”. Hence value is: “mysite.settings”
IIS manager > Sites > Sites01 > Configuration Editor > appSettings
Add module mapping:
IIS manager > Sites > Sites01 > Handler Mappings > Add Module Mapping
- Request path: *
- Module: httpPlatformHandler
- Name: -
Then, click “Request Restrictions” and unchecked “Invoked handler only if requests is mapped to”
Our “web.config” should look somewhat like this:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpPlatform processPath="C:\Python311\python.exe" arguments="C:\sites\site01\mysite\manage.py runserver %HTTP_PLATFORM_PORT%" stdoutLogEnabled="true" stdoutLogFile="C:\sites\site01\mysite\logs">
<environmentVariables>
<environmentVariable name="SERVER_PORT" value="%HTTP_PLATFORM_PORT%" />
</environmentVariables>
</httpPlatform>
<handlers>
<add name="MyPyHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
</system.webServer>
<appSettings>
<add key="PYTHONPATH" value="C:\sites\site01\mysite" />
<add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()" />
<add key="DJANGO_SETTINGS_MODULE" value="mysite.settings" />
</appSettings>
</configuration>
Navigate to “http://localhost:8001/polls”:
Option 2 — WFastCGI
I will create a new website called “site02” accessible under “http://localhost:8002”.
pip install wfastcgi
Install CGI module for IIS
PS:
Install-WindowsFeature -name Web-CGI
Close IIS Manager and open it again. Now we should be able to see a new module.
IIS Manger > Server Level > FastCGI > Add Application.
- Full Path: C:\Python311\python.exe
- Arguments: C:\Python311\Lib\site-packages\wfastcgi.py
Now we need to add our handler mapping.
IIS Manager >Sites > Site02 > Handler Mappings > Add Module Mapping
- Request Path: *
- Module: FastCgiModule
- Executable: C:\Python311\python.exe|C:\Python311\Lib\site-packages\wfastcgi.py
- Name: -
Again, “Request Restrictions” and unchecked “Invoked handler only if request is mapped to”.
Click Ok and it will prompt you if you want to create a FastCGI, but we already did it, so click no.
Last step, we need the same appsettings.
IIS Manager > Sites > Site02 > Configuration Editor > appSettings:
Browse to “http://localhost:8002/polls”
So, our “web.config” should look somewhat like this:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="MyPyHandler2" path="*" verb="*" modules="FastCgiModule" scriptProcessor="C:\Python311\python.exe|C:\Python311\Lib\site-packages\wfastcgi.py" resourceType="Unspecified" requireAccess="Script" />
</handlers>
</system.webServer>
<appSettings>
<add key="PYTHONPATH" value="C:\sites\site02\mysite" />
<add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()" />
<add key="DJANGO_SETTINGS_MODULE" value="mysite.settings" />
</appSettings>
</configuration>
And the FastCGI section stored in “C:\Windows\System32\inetsrv\Config\applicationHost.config” file:
<system.webServer>
<!-- -->
<fastCgi>
<application fullPath="C:\Python311\python.exe" arguments="C:\Python311\Lib\site-packages\wfastcgi.py" monitorChangesTo="" stderrMode="ReturnStdErrIn500" maxInstances="4" idleTimeout="300" activityTimeout="30" requestTimeout="90" instanceMaxRequests="200" signalBeforeTerminateSeconds="0" protocol="NamedPipe" queueLength="1000" flushNamedPipe="false" rapidFailsPerMinute="10" />
</fastCgi>
<!-- -->
</system.webServer>
If you want to use a domain name
You will first have to allow in in the “settings.py” ALLOWED_HOSTS.
When empty, only localhost will work.
Resources
- Configure Python web apps for IIS — Visual Studio (Windows) | Microsoft Learn
- Download Python | Python.org
- Download Django | Django (djangoproject.com)
- HttpPlatformHandler v1.2 : The Official Microsoft IIS Site
- wfastcgi · PyPI
- Writing your first Django app, part 1 | Django documentation | Django (djangoproject.com)