How to Deploy a Python Flask Application on Windows Server 2025
Python Flask is a lightweight and flexible web framework that powers everything from internal tools to production APIs. While Linux is the more common deployment platform for Python web applications, Windows Server 2025 is a fully viable host — particularly in enterprise environments where the rest of the infrastructure runs on Windows. The key to a stable Flask deployment on Windows is using a production-grade WSGI server (Flask’s built-in development server must never be used in production), configuring IIS as a reverse proxy with the httpPlatformHandler module, and running the application as a managed Windows service. This guide covers the complete process from Python installation to a fully automated service deployment using NSSM.
Prerequisites
- Windows Server 2025 with administrative privileges
- IIS installed and running (required for the reverse proxy approach)
- The
httpPlatformHandlerIIS module installed (available from the IIS.net download center) - Your Flask application code ready to deploy, with a
requirements.txtfile - A callable named
apporapplicationin your Flask entry point module - NSSM (Non-Sucking Service Manager) for Windows service creation — installable via Chocolatey
Step 1: Install Python on Windows Server 2025
Download the latest stable Python installer (3.12 or later) from https://www.python.org/downloads/windows/. Choose the Windows installer (64-bit) version. Run the installer with administrator privileges and ensure the following options are selected:
- Add Python to PATH — critical; without this you must use absolute paths for all Python commands
- Install for all users — places Python in
C:Program FilesPython312and makes it accessible to services - Install pip — required for package management
# Verify Python installation after opening a new PowerShell window
python --version
pip --version
# Expected output:
# Python 3.12.x
# pip 24.x.x from C:Program FilesPython312Libsite-packagespip (python 3.12)
Alternatively, install Python via Chocolatey for automation and easier version management:
choco install python312 -y
Step 2: Deploy Application Files and Create a Virtual Environment
Create a dedicated directory for your application and set up an isolated Python virtual environment. Virtual environments prevent package conflicts between applications on the same server:
# Create the application directory
New-Item -ItemType Directory -Path "C:Appsflaskapp" -Force
# Copy application files to the server
# (Adjust source path to match your deployment mechanism)
xcopy \fileserverreleasesflaskapp C:Appsflaskapp /E /I
# Navigate to the application directory
cd C:Appsflaskapp
# Create a virtual environment
python -m venv venv
# Activate the virtual environment
.venvScriptsActivate.ps1
# Verify the activated environment
python --version
where python
# Should show: C:AppsflaskappvenvScriptspython.exe
Step 3: Install Flask and Waitress
Waitress is the recommended WSGI server for Flask applications on Windows. It is a pure-Python server (no C extensions required), supports multiple threads, handles HTTP/1.1, and is actively maintained. Unlike Gunicorn, Waitress runs natively on Windows without compatibility shims.
# Install dependencies from requirements.txt
pip install -r requirements.txt
# Or install Flask and Waitress explicitly
pip install flask waitress
# Verify installations
pip list | findstr -i "flask waitress"
Your requirements.txt should specify pinned versions for reproducible deployments:
flask==3.1.0
waitress==3.0.1
python-dotenv==1.0.1
SQLAlchemy==2.0.36
Step 4: Test the Application with Waitress
Before configuring IIS or Windows services, verify the application starts correctly with Waitress directly. Your Flask entry point (e.g., app.py) should expose an app object at module level:
# app.py example structure
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Flask on Windows Server 2025'
if __name__ == '__main__':
app.run()
# Start with Waitress — binds to all interfaces on port 8000
waitress-serve --host=0.0.0.0 --port=8000 app:app
# For a module inside a package (e.g., myproject/wsgi.py exposing 'application')
waitress-serve --host=0.0.0.0 --port=8000 myproject.wsgi:application
# Increase threads for better concurrency under load
waitress-serve --host=0.0.0.0 --port=8000 --threads=8 app:app
Open a browser or run curl http://localhost:8000/ to confirm the application responds. Stop the process with Ctrl+C before continuing to the service setup.
Step 5: Configure IIS as a Reverse Proxy with httpPlatformHandler
The httpPlatformHandler module allows IIS to launch and manage a process (your Waitress server) and proxy requests to it automatically. This is the simplest integration method and avoids maintaining a separate Windows service for the Flask process.
First, install httpPlatformHandler from https://www.iis.net/downloads/microsoft/httpplatformhandler. Then create an IIS site pointing to your application directory and add a web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler"
path="*"
verb="*"
modules="httpPlatformHandler"
resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="C:AppsflaskappvenvScriptspython.exe"
arguments="-m waitress --host=127.0.0.1 --port=%HTTP_PLATFORM_PORT% app:app"
startupTimeLimit="60"
requestTimeout="00:04:00"
stdoutLogEnabled="true"
stdoutLogFile="C:Appslogsflaskapp-stdout.log">
<environmentVariables>
<environmentVariable name="FLASK_ENV" value="production" />
<environmentVariable name="PYTHONPATH" value="C:Appsflaskapp" />
<environmentVariable name="DATABASE_URL" value="postgresql://user:pass@dbserver/mydb" />
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
Note the use of %HTTP_PLATFORM_PORT% — httpPlatformHandler assigns a random available port and passes it to the process via this environment variable, avoiding port conflicts.
Step 6: Run as a Windows Service with NSSM
If you prefer a standalone Windows service instead of IIS-managed process startup, NSSM (Non-Sucking Service Manager) provides reliable wrapping with automatic restart and log redirection:
# Install NSSM
choco install nssm -y
# Create a Windows service named FlaskApp
nssm install FlaskApp "C:AppsflaskappvenvScriptspython.exe"
# Configure arguments
nssm set FlaskApp AppParameters "-m waitress --host=0.0.0.0 --port=8000 --threads=8 app:app"
# Set the working directory
nssm set FlaskApp AppDirectory "C:Appsflaskapp"
# Redirect stdout and stderr to log files
nssm set FlaskApp AppStdout "C:Appslogsflaskapp-stdout.log"
nssm set FlaskApp AppStderr "C:Appslogsflaskapp-stderr.log"
# Set environment variables for the service process
nssm set FlaskApp AppEnvironmentExtra "FLASK_ENV=production" "DATABASE_URL=postgresql://user:pass@dbserver/mydb"
# Set restart behavior
nssm set FlaskApp AppExit Default Restart
nssm set FlaskApp AppRestartDelay 5000
# Start the service
nssm start FlaskApp
# Set to auto-start
sc config FlaskApp start= auto
Step 7: Configure Environment Variables Securely
For secrets like database credentials and API keys, use system-level environment variables rather than hardcoding them in web.config or source code:
# Set machine-level environment variables via PowerShell
[System.Environment]::SetEnvironmentVariable("SECRET_KEY", "your-very-secret-key-here", "Machine")
[System.Environment]::SetEnvironmentVariable("DATABASE_URL", "postgresql://user:pass@server/db", "Machine")
[System.Environment]::SetEnvironmentVariable("FLASK_ENV", "production", "Machine")
In your Flask application, load these with os.environ or the python-dotenv package for local development:
import os
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'fallback-dev-key'
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
Conclusion
Your Flask application is now production-ready on Windows Server 2025: running behind Waitress as a proper WSGI server, managed either by IIS httpPlatformHandler or NSSM as a persistent Windows service, and with environment variables cleanly separated from application code. This setup handles automatic restarts on failure, integrates with Windows Event Log through NSSM, and allows IIS to handle SSL termination, static file serving, and request routing for multiple applications on the same server. As your application scales, consider enabling Waitress’s multi-threaded mode or switching to a multi-process architecture using a task queue like Celery for background jobs.