Windows標準WebサーバIISとFlaskを、httpPlatformを使って接続してみた

# はじめに

この記事では、Windowsに標準搭載されているWebサーバ（IIS）とFlaskを接続する方法を記します。

FlaskなどのPythonWebアプリケーションとIISとを接続させるのに、従来はFastCGIが一般的に使われていたようです。しかし、FastCGIのプロジェクトが維持されなくなったことから、Microsoftが**httpPlatform**の利用を推奨しています。
したがって、この記事では**httpPlatform**を使います。


# 前提

- pythonインストール済。
- IISインストール済。
- Flask入門済。

# 環境構築

## 1.Flaskアプリの準備

### app.pyの作成
今回はFlaskのチュートリアルから拝借。

```python:app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

```

### プロジェクト（フォルダ）を作成
今回は次のフォルダを作成し、ここにapp.pyを格納しました。
`C:\inetpub\wwwroot\flask\app1`

### 権限の設定
wwwroot配下では、一般ユーザに書き込み権限が付与されません。
作業がつらくなるので、一時的に書き込み権限を付与しておきます。

右クリック＞プロパティ＞セキュリティ＞編集

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/e2ceb850-3b20-231d-3aec-207a66367308.png)

書き込みを許可にしてOKボタンをクリック。

### Pythonモジュールのリストを作成
app.pyと同じ階層にrequirements.txtを作成します。
今回必要なのは、Flaskだけですね。
アプリに必要な分だけ追記します。
```
flask==2.0.1
```
### Pythonの仮想環境を作成
コマンドプロンプトを起動してプロジェクトフォルダに移動後、次のコマンドを実行。
```console
python -m venv myvenv
myvenv\scripts\activate
```

ここからのコマンドは全て仮想環境下で行います。

### Pythonのモジュールをインストール
どばばばば。
```console
pip install -r requirements.txt
```

### Flaskの起動確認。

念のために一旦、単体で起動できることを確認しておきます。

``` console
set FLASK_APP=app
python -m flask run --port 5001
```

http://localhost:5001/
にアクセス。Hello!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/5a56a9d7-a93a-e977-0905-18d7cb8e5249.png)

確認できれば停止。

## 2.IISのプロジェクト作成～起動確認
### web.configを作成

IISが用いるconfigファイルを、**web.config**と名付けてapp.pyと同じ階層に保存します。
web.configの内容については、Microsoftさんが用意してくださったサンプルと説明を参考にします。


```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
        <!-- httpPlatformモジュールを追加 -->
        <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />　 
    </handlers>
    <httpPlatform 
          processPath="C:\inetpub\wwwroot\flask\app1\myvenv\Scripts\python.exe" 
          arguments="-m flask run --port %HTTP_PLATFORM_PORT%"
          stdoutLogEnabled="true"
          stdoutLogFile="C:\inetpub\wwwroot\flask\app1\log\app1_log"
          startupTimeLimit="60" processesPerApplication="16"
          >
      <environmentVariables>
        <environmentVariable name="FLASK_APP" value="C:\inetpub\wwwroot\flask\app1\app.py" />
      </environmentVariables>
    </httpPlatform>
  </system.webServer>
</configuration>
```

- 参考
    - [IIS 用に Python Web アプリを構築する](https://learn.microsoft.com/ja-jp/visualstudio/python/configure-web-apps-for-iis-windows?view=vs-2022)
    - [httpPlatformの詳細説明](https://learn.microsoft.com/ja-jp/previous-versions/azure/windows-server-azure-pack/mt125371(v=technet.10)#webconfig-httpplatform-configuration)

### ログ格納フォルダを作成
空ファイルを作成しておきます。
```
C:\inetpub\wwwroot\flask\app1\log\log.txt
```


### httpPlatformをインストール

インストーラをダウンロードして実行します。

- インストーラ：https://www.iis.net/downloads/microsoft/httpplatformhandler

### IISを起動し、Webサイトを追加する。
Windowsキー→IISと入力
IISマネージャを起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/ba4dad50-01b3-c53c-e47f-23509466a030.png)

Webサイトを追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/788bdffb-ee73-451f-af21-718c1d3a5ec7.png)

赤線部を入力してOKボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/50979979-68a2-25fc-0c71-a854cb5691f7.png)

サイトが追加される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/35eda995-0bcb-2a5c-dcd7-91c7c890159c.png)

### 追加したページにアクセスしてみる

- http://localhost:8000/

エラーが出る。この時点ではHelloしてくれない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/7659e10f-c54b-debf-9c4e-f3ddcde117bb.png)

### applicationHost.configを編集


`C:\Windows\System32\inetsrv\config\applicationHost.config`を編集する。

```xml:applicationHost.config（変更前）
<section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
```

```xml:applicationHost.config（変更後）
<section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
```

- 参考
    - Error 500.19の原因：https://engineers.fenrir-inc.com/entry/2021/12/03/180406
        - ASP.NET、ISAPIフィルター、ISAPI拡張がインストールされていない
        - C:\Windows\System32\inetsrv\config\applicationHost.config の編集が必要

### アクセスしても応答がない。
- http://localhost:8000/
読み込み中のまま画面表示されない状態になります。


### IIS_IUSRSの権限を設定する

- プロジェクトフォルダに書き込み権限を与えて、ログ出力できるようにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/d2711381-3ffe-6818-6d97-62a51a9aaa7b.png)

- PythonのインストールフォルダにIIS_IUSRSのアクセス権限を付与する。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/20864aad-3bf4-58cd-43da-44ed49ef42c4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/f3c5c5eb-6775-db3b-f7a1-623accdb4a24.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/4a82be6b-163b-e075-1e25-88a2ec1d0a32.png)


### 完走

ようやく辿り着きました。Hello。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630591/d0fe4bb4-3be0-6078-4dce-2a028c8f936a.png)


## 感想

時間がかかった・・・。
権限の付与に関する部分は試行錯誤して随分時間をかけてしまった。
httpPlatformはDjangoやらNode.jsやらにも応用できるらしいです。
乗り越えておいてよかったと信じておきます。