|
| 1 | +--- |
| 2 | +title: Configuring Python web apps for IIS |
| 3 | +description: How to configure Python web apps to run with Internet Information Services from a Windows virtual machine. |
| 4 | +ms.date: 10/10/2018 |
| 5 | +ms.prod: visual-studio-dev15 |
| 6 | +ms.technology: vs-python |
| 7 | +ms.topic: conceptual |
| 8 | +author: kraigb |
| 9 | +ms.author: kraigb |
| 10 | +manager: douge |
| 11 | +ms.workload: |
| 12 | + - python |
| 13 | + - data-science |
| 14 | + - azure |
| 15 | +--- |
| 16 | + |
| 17 | +# Configure Python web apps for IIS |
| 18 | + |
| 19 | +When using Internet Information Services (IIS) as a web server on a Windows computer (including [Windows virtual machines on Azure](/azure/architecture/reference-architectures/n-tier/windows-vm), Python apps must include specific settings in their *web.config* files so that IIS can properly process Python code. The computer itself must also have Python installed along with any packages the web app requires. |
| 20 | + |
| 21 | +> [!Note] |
| 22 | +> This article previously contained guidance for configuring Python on Azure App Service on Windows. The Python extensions and Windows hosts used in that scenario have been deprecated in favor of Azure App Service on Linux. For more information, see [Publishing Python Apps to Azure App Service](publishing-python-web-applications-to-azure-from-visual-studio.md) |
| 23 | +
|
| 24 | +## Install Python on Windows |
| 25 | + |
| 26 | +To run a web app, first install your required version of Python directly on the Windows host machine as described on [Install Python interpreters](installing-python-interpreters.md). |
| 27 | + |
| 28 | +Record the location of the `python.exe` interpreter for later steps. For convenience, you can add that location to your PATH environment variable. |
| 29 | + |
| 30 | +## Install packages |
| 31 | + |
| 32 | +When using a dedicated host, you can use the global Python environment to run your app rather than a virtual environment. Accordingly, you can install all of your app's requirements into the global environment simply by running `pip install -r requirements.txt` at a command prompt. |
| 33 | + |
| 34 | +## Set web.config to point to the Python interpreter |
| 35 | + |
| 36 | +Your app's *web.config* file instructs the IIS (7+) web server running on Windows about how it should handle Python requests through either FastCGI or HttpPlatform. When using Visual Studio 2017, you must modify *web.config* manually. As described in a later section, Visual Studio 2015 makes modifications |
| 37 | + |
| 38 | +### Configure the HttpPlatform handler |
| 39 | + |
| 40 | +The HttpPlatform module passes socket connections directly to a standalone Python process. This pass-through allows you to run any web server you like, but requires a startup script that runs a local web server. You specify the script in the `<httpPlatform>` element of *web.config*, where the `processPath` attribute points to the site extension's Python interpreter and the `arguments` attribute points to your script and any arguments you want to provide: |
| 41 | + |
| 42 | +```xml |
| 43 | +<?xml version="1.0" encoding="utf-8"?> |
| 44 | +<configuration> |
| 45 | + <system.webServer> |
| 46 | + <handlers> |
| 47 | + <add name="PythonHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/> |
| 48 | + </handlers> |
| 49 | + <httpPlatform processPath="c:\python36-32\python.exe" |
| 50 | + arguments="c:\home\site\wwwroot\runserver.py --port %HTTP_PLATFORM_PORT%" |
| 51 | + stdoutLogEnabled="true" |
| 52 | + stdoutLogFile="c:\home\LogFiles\python.log" |
| 53 | + startupTimeLimit="60" |
| 54 | + processesPerApplication="16"> |
| 55 | + <environmentVariables> |
| 56 | + <environmentVariable name="SERVER_PORT" value="%HTTP_PLATFORM_PORT%" /> |
| 57 | + </environmentVariables> |
| 58 | + </httpPlatform> |
| 59 | + </system.webServer> |
| 60 | +</configuration> |
| 61 | +``` |
| 62 | + |
| 63 | +The `HTTP_PLATFORM_PORT` environment variable shown here contains the port that your local server should listen on for connections from localhost. This example also shows how to create another environment variable, if desired, in this case `SERVER_PORT`. |
| 64 | + |
| 65 | +### Configure the FastCGI handler |
| 66 | + |
| 67 | +FastCGI is an interface that works at the request level. IIS receives incoming connections and forwards each request to a WSGI app running in one or more persistent Python processes. |
| 68 | + |
| 69 | +To use it, first install and configure the wfastcgi package as described on [pypi.org/project/wfastcgi/](https://pypi.io/project/wfastcgi). |
| 70 | + |
| 71 | +Next, modify your app's *web.config* file to include the full paths to *python.exe* and *wfastcgi.py* in the `PythonHandler` key. The steps below assume that Python is installed in *c:\python36-32* and that your app code is in *c:\home\site\wwwroot*; adjust for your paths accordingly: |
| 72 | + |
| 73 | +1. Modify the `PythonHandler` entry in *web.config* so that the path matches the Python install location (see [IIS Configuration Reference](https://www.iis.net/configreference) (iis.net) for exact details). |
| 74 | + |
| 75 | + ```xml |
| 76 | + <system.webServer> |
| 77 | + <handlers> |
| 78 | + <add name="PythonHandler" path="*" verb="*" modules="FastCgiModule" |
| 79 | + scriptProcessor="c:\python36-32\python.exe|c:\python36-32\wfastcgi.py" |
| 80 | + resourceType="Unspecified" requireAccess="Script"/> |
| 81 | + </handlers> |
| 82 | + </system.webServer> |
| 83 | + ``` |
| 84 | + |
| 85 | +1. Within the `<appSettings>` section of *web.config*, add keys for `WSGI_HANDLER`, `WSGI_LOG` (optional), and `PYTHONPATH`: |
| 86 | + |
| 87 | + ```xml |
| 88 | + <appSettings> |
| 89 | + <add key="PYTHONPATH" value="c:\home\site\wwwroot"/> |
| 90 | + <!-- The handler here is specific to Bottle; see the next section. --> |
| 91 | + <add key="WSGI_HANDLER" value="app.wsgi_app()"/> |
| 92 | + <add key="WSGI_LOG" value="c:\home\LogFiles\wfastcgi.log"/> |
| 93 | + </appSettings> |
| 94 | + ``` |
| 95 | + |
| 96 | + These `<appSettings>` values are available to your app as environment variables: |
| 97 | + |
| 98 | + - The value for `PYTHONPATH` may be freely extended but must include the root of your app. |
| 99 | + - `WSGI_HANDLER` must point to a WSGI app importable from your app. |
| 100 | + - `WSGI_LOG` is optional but recommended for debugging your app. |
| 101 | + |
| 102 | +1. Set the `WSGI_HANDLER` entry in *web.config* as appropriate for the framework you're using: |
| 103 | + |
| 104 | + - **Bottle**: make sure that you have parentheses after `app.wsgi_app` as shown below. This is necessary because that object is a function (see *app.py*) rather than a variable: |
| 105 | + |
| 106 | + ```xml |
| 107 | + <!-- Bottle apps only --> |
| 108 | + <add key="WSGI_HANDLER" value="app.wsgi_app()"/> |
| 109 | + ``` |
| 110 | + |
| 111 | + - **Flask**: Change the `WSGI_HANDLER` value to `<project_name>.app` where `<project_name>` matches the name of your project. You can find the exact identifier by looking at the `from <project_name> import app` statement in the *runserver.py*. For example, if the project is named "FlaskAzurePublishExample", the entry would appear as follows: |
| 112 | + |
| 113 | + ```xml |
| 114 | + <!-- Flask apps only: change the project name to match your app --> |
| 115 | + <add key="WSGI_HANDLER" value="flask_iis_example.app"/> |
| 116 | + ``` |
| 117 | + |
| 118 | + - **Django**: Two changes are needed to *web.config* for Django projects. First, change the `WSGI_HANDLER` value to `django.core.wsgi.get_wsgi_application()` (the object is in the *wsgi.py* file): |
| 119 | + |
| 120 | + ```xml |
| 121 | + <!-- Django apps only --> |
| 122 | + <add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()"/> |
| 123 | + ``` |
| 124 | + |
| 125 | + Second, add the following entry below the one for `WSGI_HANDLER`, replacing `DjangoAzurePublishExample` with the name of your project: |
| 126 | + |
| 127 | + ```xml |
| 128 | + <add key="DJANGO_SETTINGS_MODULE" value="django_iis_example.settings" /> |
| 129 | + ``` |
| 130 | + |
| 131 | +1. **Django apps only**: In the Django project's *settings.py* file, add your site URL domain or IP address to `ALLOWED_HOSTS` as shown below, replacing '1.2.3.4' with your URL or IP address, of course: |
| 132 | + |
| 133 | + ```python |
| 134 | + # Change the URL or IP address to your specific site |
| 135 | + ALLOWED_HOSTS = ['1.2.3.4'] |
| 136 | + ``` |
| 137 | + |
| 138 | + Failure to add your URL to the array results in the error **DisallowedHost at / Invalid HTTP_HOST header: '\<site URL\>'. You may need to add '\<site URL\>' to ALLOWED_HOSTS.** |
| 139 | + |
| 140 | + Note that when the array is empty, Django automatically allows 'localhost' and '127.0.0.1', but adding your production URL removes those capabilities. For this reason you might want to maintain separate development and production copies of *settings.py*, or use environment variables to control the run time values. |
| 141 | + |
| 142 | +## Deploy to IIS or a Windows VM |
| 143 | + |
| 144 | +With the correct *web.config* file in your project, you can publish to the computer running IIS by using the **Publish** command on the project's context menu in **Solution Explorer**, and selecting the option, **IIS, FTP, etc.**. In this case, Visual Studio simply copies the project files to the server; you're responsible for all server-side configuration. |
0 commit comments