Running Django Web Apps on IIS with HttpPlatformHandler
A post about how to create a simple Django web app and host it on IIS with HttpPlatformHandler
HttpPlatformHandler can help IIS host Java/Python/Node.js/Go applications, so in this post we wil see how to configure a Python/Django web app on IIS and troubleshoot the common issue.
It becomes very important for Python developers to learn HttpPlatformHandler, because Microsoft no longer recommends FastCGI,
“We recommend using HttpPlatform to configure your apps, as the WFastCGI project is no longer maintained.”
Prerequisites
To follow this post, you need to have the following software installed,
- Windows 10 or Windows Server 2016 or later (IIS 10 or later)
- HttpPlatformHandler v1.2 (from Microsoft) or v2.0 (from LeXtudio)
Basic Django Setup
No doubt we will start from a sample application as below.
1
2
cd C:\test-django
C:\Users\lextudio\AppData\Local\Programs\Python\Python310\python.exe -m django startproject mysite
This generates a Django project in C:\test-django\mysite
, and now we can use a simple command python.exe manage.py runserver
in the directory of C:\test-django\mysite
can launch the application at port 8000,
1
2
3
4
5
6
7
8
9
10
11
12
13
$ cd mysite
$ C:\Users\lextudio\AppData\Local\Programs\Python\Python310\python.exe manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 30, 2024 - 21:58:13
Django version 5.0.3, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
If Python and Django are not yet installed, you can search for guides.
HttpPlatformHandler Setup
Now let’s download and install HttpPlatformHandler on IIS, and add a web.config
in C:\test-django\mysite
,
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script" />
</handlers>
<httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\python.log" startupTimeLimit="20" processPath="C:\Users\<user name>\AppData\Local\Programs\Python\Python310\python.exe" arguments="manage.py runserver %HTTP_PLATFORM_PORT%">
</httpPlatform>
</system.webServer>
</configuration>
With all settings in place, I can go back to IIS Manager and create a site (I chose *:8014 as site binding) to point to C:\test-django\mysite
. By opening a web browser and navigate to http://localhost:8014/
, I should now see the default Django welcome page saying “The install worked successfully! Congratulations!”.
Troubleshooting
Well if you hit any error instead of the default page, please refer to my old post for troubleshooting tips.
Production Setup with Uvicorn and WhiteNoise
The above setup is for development only, and you should use a production-ready server like Uvicorn and a static file serving mechanism like WhiteNoise when deploying to production.
First, run python.exe manage.py check --deploy
to see if there are any issues to fix. Typical changes at this stage in settings.py
include
1
2
3
4
5
6
DEBUG = False
ALLOWED_HOSTS = ['*']
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
STATIC_ROOT = BASE_DIR / 'static'
MEDIA_ROOT = BASE_DIR / 'media'
To learn more about them (and many other key settings), you can visit this Django checklist.
Then, install Uvicorn and WhiteNoise.
1
python.exe -m pip install uvicorn whitenoise
Finally, enable WhiteNoise in settings.py
,
1
2
3
4
5
6
7
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # add WhiteNoise middleware after SecurityMiddleware.
# ...
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
The steps were taken from WhiteNoise docs.
One extra step needed here is to move all static files to a central folder,
1
python.exe manage.py collectstatic
This is not only applicable to WhiteNoise, but also to other static file serving mechanisms. But you must do this step after enabling WhiteNoise in
settings.py
, as the generated files are different with and without WhiteNoise.
With all these changes, you can now run Uvicorn to serve the Django application,
1
2
3
4
5
6
$ python.exe -m uvicorn mysite.asgi:application
INFO: Started server process [7072]
INFO: Waiting for application startup.
INFO: ASGI 'lifespan' protocol appears unsupported.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
The Django project already has
asgi.py
, which can be used by Uvicorn to start the application.
At this point, your web.config
should be updated to use Uvicorn instead of Django’s development server,
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script" />
</handlers>
<httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\python.log" startupTimeLimit="20" processPath="C:\Users\<user name>\AppData\Local\Programs\Python\Python310\python.exe" arguments="-m uvicorn mysite.asgi:application --port %HTTP_PLATFORM_PORT%">
</httpPlatform>
</system.webServer>
</configuration>
You can see how smooth the experience is, compared to what other guides suggest.
Side Notes
Static files can be served by mechanisms other than WhiteNoise, if you dig further into Django documentation.
You can choose other application server other than Uvicorn, but the key is to use HttpPlatformHandler to host the application on IIS.
Django on IIS Express
You can take a look at the new open source HttpPlatformHandler v2.0 from LeXtudio.
Other Languages on IIS?
If you want to learn more about HttpPlatformHandler and how to host other languages (Go/Node.js/Java) or frameworks (FastAPI/Flask), you can read this post.