Let’s be honest: I’m not a DevOps expert, and maybe you aren’t either. I just wanted to see if I could actually get Django running on Windows without falling into the old FastCGI traps. I’ve already tinkered with Apache and Nginx, so I figured this would be the next logical project, seeing if we can actually launch this on IIS. Most guides make it look like a nightmare, but here is another implementation I’ve been working on. We’re going to use the HttpPlatformHandler to bridge IIS with Uvicorn. By isolating our Python environment in one folder and the app logic in another, we’re building a setup that is clean, fast, and honestly, pretty satisfying to see in action.
Before we touch a single file, the best advice I can give from this experiment is to use a virtual machine, I personally used one with Windows 11 to keep your host system clean and allow you to test everything safely until you have mastered every step.
Go to your C: Drive (inside your Virtual Machine) and create:
C:\project→ The main root.C:\project\app→ Your Django(6.0.2) project code.C:\project\python→ Python environment (3.14.3).C:\project\postgresql— Database installation/binaries(18.1).C:\project\logs→ The “Black Box” (Where we track errors).
1 . Installing Python 3.14
Go to python.org and download the latest stable installer for your specific version of Windows (64-bit or 32-bit).
Instead of the default “one-click” setup, we will perform a controlled installation to C:\project\python
- Run the installer and check Add python.exe to PATH at the bottom
- Choose Customize installation and click Next through the features
- Under Advanced Options select Install for all users and change the Customize install location to:
C:\project\python - After installation, if prompted, click Disable path length limit. This is a life-saver for Django projects with many dependencies
2. Install PostgreSQL
Go to the PostgreSQL Windows Downloads and grab the latest version
- Run the installer. To keep everything consistent with our “root directory” philosophy, you can change the installation path to
C:\project\postgresql - Aside from the custom installation path, leave all other settings at their default values (including the Port
5432and Locale) - During setup, you’ll be asked to create a password for the
postgresuser. Keep this safe. You will need it in a moment to link Django to the database
Preparing the Database
- Open pgAdmin 4 (the management tool installed with Postgres).
- Right-click Databases > Create > Database….
- Name it
djangoand click Save.
3 . Install IIS & HttpPlatformHandler (The Web Server)
By default, Windows has IIS turned off. We need to wake it up and give it the specific tools it needs to serve a Django app.
- Press the
Windows Key, type “Turn Windows features on or off”, and hit Enter - Find Internet Information Services and check the box and expand the options
- Expand World Wide Web Services > Application Development Features, check WebSocket Protocol (Uvicorn loves this) and CGI (just as a backup for compatibility).
- Expand World Wide Web Services > Common HTTP Features.
- Make sure Static Content and Default Document are checked (you’ll need these for your CSS and Images)
- Web Management Tools check IIS Management Console
- Click OK. Windows will take a minute to install the server. You don’t usually need to reboot, but it doesn’t hurt.
Download and install the HttpPlatformHandler v1.2. This module allows IIS to launch any process (like Python/Uvicorn) and manage the traffic between them. Run Installer and follow the prompts to complete the installation.
Go to the official IIS downloads page: Microsoft URL Rewrite Module to download and install the URL Rewrite version compatible with your system (usually x64), as this module is essential for IIS to properly process the redirection rules and clean URLs required by your Django application.
4 . Environment Setup & Project Initialization
Open Command Prompt as Administrator. We will set up the virtual environment inside the project folder and activate the virtual environment:
cd C:\project\app
python -m venv venv
venv\Scripts\activate
Now we will install dependencies with the virtual environment activate.
A Quick Check: Is your Venv Active?
Before you run the installation command, take a second to look at your Command Prompt. You should see (venv) in parentheses at the very beginning of the line, like this:
(venv) C:\project\app>
pip install django uvicorn httptools psycopg2
Create the django project(myproject) in the root folder app, the . after myproject is important to have the manage.py file in app folder:
django-admin startproject myproject .
Open and ensure C:\project\app\myproject\settings.pySTATIC_ROOT is defined:
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'static'
In the same file, locate the DATABASES section. We will replace the default SQLite configuration with your PostgreSQL connection parameters.
Make sure to change the settings below with the actual name of your database and the password you set for the postgres user during installation:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'django',
'USER': 'postgres',
'PASSWORD': 'your_password_here',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
Run the collection of static files so the static files will be moved in the static folder, we will need this for the admin dashboard:
python manage.py collectstatic
python manage.py migrate
Now, let’s create a superuser so we can test our site. Of course, we could test without one, but this is just to be sure that everything is connected correctly:
python manage.py createsuperuser
Follow the prompts for username, email, and password. (Note: Windows terminals won’t show the password as you type it—just type it blindly and hit Enter!)
In your project root (the same folder as manage.py), create a file named web.config. This file tells the HttpPlatformHandler how to launch Uvicorn.
The path should be here if you followed the same structure C:\project\app\web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="PythonHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="C:\project\app\venv\Scripts\python.exe"
arguments="-m uvicorn myproject.asgi:application --port %HTTP_PLATFORM_PORT% --workers 2"
stdoutLogEnabled="true"
stdoutLogFile="C:\project\logs\uvicorn.log"
startupTimeLimit="60">
<environmentVariables>
<environmentVariable name="PYTHONPATH" value="C:\project\app" />
<environmentVariable name="DJANGO_SETTINGS_MODULE" value="myproject.settings" />
</environmentVariables>
</httpPlatform>
<rewrite>
<rules>
<rule name="StaticFiles" stopProcessing="true">
<match url="^static/.*" />
<action type="None" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Run these two commands in an Administrator Command Prompt to unlock the IIS configuration sections, allowing your project’s web.config to define the custom handlers and modules required to run Python:
%windir%\system32\inetsrv\appcmd.exe unlock config -section:system.webServer/handlers
%windir%\system32\inetsrv\appcmd.exe unlock config -section:system.webServer/modules
These commands are necessary because IIS, by default, locks these sections for security reasons; unlocking them grants the web server permission to delegate request handling to the httpPlatformHandler and your Django application.
5 . Create the Site in IIS Manager
By default, IIS comes with a pre-configured “Default Web Site” running on port 80, you must stop or delete this site to free up the port for your Django application, allowing your project to handle incoming traffic without conflicts. To do this, open IIS Manager (type inetmgr in the Start menu), navigate to the Sites folder, right-click on Default Web Site, and select Manage Website -> Stop.
⚠WARNING: Only stop or delete the “Default Web Site” if this is a fresh IIS installation or if you are certain no other services are using it. If your server is already hosting active websites, stopping this site might take them offline. In that case, instead of stopping it, you should assign a different port or a specific Host Name to your Django application to avoid port conflicts.
Now, let’s link our project to the actual web server interface.
- Open IIS Manager (type
inetmgrin the Start menu). - Right-click Sites in the left panel and select Add Website.
- Site name:
DjangoUvicornApp - Physical path:
C:\project\app - Binding:
- Type: http
- Port: 80
- Click OK.
To ensure your application runs securely, you must grant the IIS AppPool user access to your project folder by right-clicking the C:\project\app directory, navigating to Security, and adding IIS AppPool\ with Read & Execute and List folder contents permissions; this provides the server with the necessary rights to access your code and run the Python executable from the virtual environment.DjangoUvicornApp
IIS uses a specific identity to run your site.
- Right-click your project folder (
C:\projecct\app) > Properties > Security. - Click Edit > Add.
- Enter
IIS AppPool\DjangoUvicornApp(use the exact name you gave the site). - Check Read & Execute, List folder contents, and Read. Click Ok.
Since the web.config sends all requests to Uvicorn, we need to tell IIS to handle the /static/ folder separately for better performance.
- In IIS Manager, expand your site.
- Right-click your site > Add Virtual Directory.
- Alias:
static - Physical path:
C:\project\app\static - Remove the Handler for this folder:
- Click on the new
staticfolder in IIS. - Open Handler Mappings.
- Select
PythonHandlerand click Remove from the right-hand Actions pane. - This ensures IIS serves images/CSS directly instead of passing them to Django.
- Click on the new
Follow the same steps used for the C:\project\app folder to grant permissions for the C:\project\logs directory, but ensure that for this folder you also check the Write and Modify boxes; this is essential because, unlike the application code, the log folder must allow the IIS AppPool\DjangoUvicornApp user to create and update files as the project runs.
To apply all the changes, you must restart the IIS server; in IIS Manager, select your Server Name in the left “Connections” pane, and then click Restart under the “Manage Server” section in the right-side “Actions” pane. Once the restart is complete, open your web browser and navigate to http://localhost to confirm that your Django application is loading correctly.
If the Django landing page (the “The install worked successfully!” screen) loads at http://localhost, then everything is fully functional; however, if you see a “500 Internal Server Error” or the page fails to load, you should check the files in C:\project\logs to identify the specific error causing the issue.
After confirming the landing page works, navigate to http://localhost/admin to check if your static files are loading correctly, if the admin login page appears with its full design and CSS styling, your configuration is perfect. However, if the page appears as broken, plain text without any styling, it indicates that IIS is unable to serve your static assets, and you should verify your static folder path and permissions.
Security & Production Disclaimer
This setup is designed as a functional local playground. While it successfully connects all the professional components of the stack, it is not yet “hardened” for the public internet.
Before moving this project to a live server, you must follow official security guides and address these critical points:
Follow the Experts: Always consult the official Django Deployment Checklist and Microsoft’s IIS Security Best Practices before going live.
Django Hardening: Change your SECRET_KEY, set DEBUG = False, and configure ALLOWED_HOSTS.
IIS Security: You must configure IIS more strictly by disabling unnecessary headers, setting up a firewall (like Windows Firewall or a WAF), and implementing SSL/HTTPS using proper certificates.
Environment Safety: Ensure your Virtual Environment and sensitive files (like .env or your database) are protected with strong, unique passwords and are not accessible from outside your local network.
Process Management: Ensure your process manager (Uvicorn or httpPlatformHandler) is running under a low-privileged account (like the IIS AppPool user we configured).
Leave a Reply