Post

Running Django Web Apps 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.

© Lex Li. All rights reserved. The code included is licensed under CC BY 4.0 unless otherwise noted.
Advertisement

© - Lex Li. All rights reserved.

Using the Chirpy theme for Jekyll.

Last updated on April 19, 2024