Deploy Django on Windows Server With IIS
Deploy Django on Windows Server behind IIS: run Waitress through HttpPlatformHandler instead of the unmaintained wfastcgi, serve static files from IIS, run it under an app pool identity, and add HTTPS with an IIS binding.
Problem statement
Your organisation runs Windows Server, and the Django app has to live there behind IIS, the standard web server for Windows. Most Django deployment guides assume Linux with Gunicorn, which does not run on Windows. Older Windows guides use wfastcgi, which Microsoft no longer maintains and which has known problems with recent Python versions.
The current, supportable approach is to run a Windows-compatible WSGI server such as Waitress and let IIS manage and proxy to it with the HttpPlatformHandler module. IIS starts the Python process, passes it a port, restarts it if it crashes, and serves static files and TLS itself.
- Install Python for all users, create a virtualenv for the project, and
pip install waitress. - Install IIS with the HttpPlatformHandler module.
- Add a
web.configthat launchespython -m waitress --port=%HTTP_PLATFORM_PORT% config.wsgi:application. - Serve
STATIC_ROOTas an IIS virtual directory at/static, or use WhiteNoise. - Grant the app pool identity read access to the project and write access to log and media folders.
- Add an HTTPS binding with a certificate and set Django's proxy SSL settings.
Step-by-step solution
1. Install Python and the project
Install Python 3.12+ from python.org with "Install for all users" so the app pool can access it, for example in C:\Python312. Then:
cd C:\sites\myapp
C:\Python312\python.exe -m venv .venv
.venv\Scripts\pip install -r requirements.txt waitress
.venv\Scripts\python manage.py collectstatic --noinput
.venv\Scripts\python manage.py migrate
Use PostgreSQL, SQL Server (with the mssql-django backend), or MySQL; set connection details through environment variables.
2. Install IIS and HttpPlatformHandler
In Server Manager add the Web Server (IIS) role with Static Content, then install the HttpPlatformHandler (v1.2) from Microsoft. Create a site pointing at C:\sites\myapp with its own application pool set to "No Managed Code".
3. Configure web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="C:\sites\myapp\.venv\Scripts\python.exe"
arguments="-m waitress --listen=127.0.0.1:%HTTP_PLATFORM_PORT% --threads=8 config.wsgi:application"
stdoutLogEnabled="true"
stdoutLogFile="C:\sites\myapp\logs\waitress.log"
startupTimeLimit="60"
processesPerApplication="1">
<environmentVariables>
<environmentVariable name="DJANGO_SETTINGS_MODULE" value="config.settings.production" />
<environmentVariable name="PYTHONUNBUFFERED" value="1" />
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
IIS chooses a free port, sets HTTP_PLATFORM_PORT, starts Waitress, and proxies requests to it. Keep secrets out of web.config in source control; set them as system environment variables or in a separate config transform applied at deploy time.
4. Serve static and media files from IIS
Add a virtual directory /static pointing at STATIC_ROOT (for example C:\sites\myapp\staticfiles) and /media pointing at MEDIA_ROOT. In each folder add a web.config that removes the HttpPlatformHandler so IIS serves files directly:
<configuration>
<system.webServer>
<handlers>
<remove name="httpPlatformHandler" />
</handlers>
</system.webServer>
</configuration>
Alternatively, WhiteNoise serves static files from Django itself, which keeps IIS configuration minimal.
5. Permissions
The app pool runs as IIS AppPool\<PoolName>. Grant it:
- Read and execute on the project, the virtualenv, and Python itself.
- Modify on
logs\and the media folder.
icacls C:\sites\myapp /grant "IIS AppPool\myapp:(OI)(CI)RX"
icacls C:\sites\myapp\logs /grant "IIS AppPool\myapp:(OI)(CI)M"
6. HTTPS
Add an HTTPS binding to the site with a certificate (from your CA, or Let's Encrypt via a Windows ACME client such as win-acme). Since IIS terminates TLS and proxies to Waitress over HTTP, tell Django:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
HttpPlatformHandler forwards X-Forwarded-Proto when forwardWindowsAuthToken and related options are configured; verify with a debug view, or have Waitress trust IIS's headers with --trusted-proxy=127.0.0.1 --trusted-proxy-headers=x-forwarded-proto.
Verification check: browse the site over HTTPS, confirm static files load (check the Server: Microsoft-IIS header on a CSS file), check logs\waitress.log for startup messages, and recycle the app pool to confirm Waitress restarts cleanly.
Explanation
Gunicorn depends on Unix process forking, so it does not run on Windows. Waitress is a production-quality, pure-Python WSGI server that uses threads and works on Windows. HttpPlatformHandler is an IIS module designed to host any process that listens on HTTP: it launches the process with an assigned port, proxies requests to it, and restarts it on failure, giving the same supervision that systemd provides on Linux. IIS keeps doing what it does best: TLS, static files, Windows authentication, and integration with Windows administration tools.
Edge cases / notes
- Celery on Windows is not officially supported for the worker; use
--pool=solofor light use, or run workers on Linux. - Long paths. Enable long path support in Windows if dependencies have deep directory trees.
- Antivirus scanning the virtualenv can slow startup significantly; exclude the project folder if policy allows.
- ASGI. For async needs, Uvicorn runs on Windows behind the same handler, without uvloop.
Next steps
- Simplify static files with Serve Static Files With WhiteNoise in Django.
- Review settings with the Django Production Settings Checklist.
FAQ
Can Django run on IIS?
Yes. Run Django with Waitress and let IIS host it through HttpPlatformHandler.
Should I use wfastcgi?
No. It is no longer maintained. HttpPlatformHandler with Waitress is the supportable approach.
Does Gunicorn work on Windows?
No. Gunicorn relies on Unix features. Waitress is the common Windows alternative.
How does IIS serve Django static files?
With virtual directories for /static and /media that bypass the Python handler, or with WhiteNoise inside Django.