'sqr'atch-note

ちりはつもれど ちりぬるを

mod_wsgiを使ってApacheでFlaskアプリを公開

  • だいぶ前の話で、Flaskアプリ本を読んだ時に作ったアプリはnginxで公開したけど、Apacheだとどうなるのかなと思ってやってみた。Apache + Flaskみたいな単語でググると色々と説明記事がヒットするものの、大体中途半端だったり、古かったりしたので、だいぶ困った。いろいろ調べた結果、mod_wsgiの公式ページを読めばすべて書いてあるし、ここを読んでさえいれば十分だと分かった。
  • 今回試した環境は以下の通り。
    • Rocky Linux release 8.7 (Green Obsidian)
    • Python 3.9.13
    • Server version: Apache/2.4.37 (rocky)

公式ページ

はじめに

  • mod_wsgiをインストールする方法は2つあって、まずApacheのDSOとしてmake&make installする方法、そしてPythonのパッケージとしてインストールする方法。
  • 本記事では、後者のPythonのパッケージとしてインストールする方法を扱う。
  • Flaskアプリは、venv環境を利用している想定とする。

Pythonのインストール

  • Rocky Linux 8のminimal Installでは、platform-pythonと呼ばれるシステムの処理用Pythonしかインストールされていない。これを使ってユーザのスクリプトを実行するのは非推奨となっている
  • そのため、まずPythonのインストールをする
    • dnf install python39 python39-devel
    • 後々、mod_wsgiをインストールする際に必要となるのでpython39-develもインストールしておく

mod_wsgiのインストール

  • Pythonのパッケージとしてインストールする場合、python3 -m pip install mod_wsgipip3 install mod_wsgiで処理されるランタイムが異なるので、複数バージョンのPythonがインストールされている環境では注意が必要。
    • pip3コマンドを使うと、pip3をインストールしたPythonバージョンが使用されるため、複数バージョンのPythonが入っている環境では想定と違うバージョンが使われる場合がある。
  • 今回は、venv環境下でpython3 -m pip install mod_wsgiによりインストールする。
## ビルドするためにgccなどが必要なので開発ツールをグループインストールする
dnf group install 'Development Tools'
## mod_wsgiのビルドにApacheのヘッダファイルが必要なのでインストールしておく
dnf install httpd-devel

## venv環境をアクティベートしてから、mod_wsgiのインストール
source bin/activate
(myenv) python3 -m pip install mod_wsgi

## インストールロケーションの確認
(myenv) pip3 show mod_wsgi

mod_wsgiの使用

  • mod_wsgiを使う方法も2つある。
  • 1つは、Pythonのパッケージとしてインストールしたら付属してくるツールmod_wsgi-expressを使う方法。
    • この方法は、Apacheのディレクティブを書かなくてもツールがよしなしやってくれるので楽。ただし、アプリが公開されるポート番号はデフォルトだと8000/tcpとなる(80/tcpなどで実行させたい場合は別途オプション設定が必要となる)。開発用途では、いちいちディレクティブを書かなくて良いmod_wsgi-expressを使うのが良いと思う。
  • 2つ目は、システムにインストールされたhttpdプロセスでWSGIモジュールをロードして使う方法。本記事では、こちらの方法を採用する。

準備

  • まず、何はともあれwsgiファイルを用意してあげる。
  • Flaskの最小アプリケーションは、create_app関数を利用したものを用意する。以下のコードをapp.pyとして保存する。
from flask import Flask
def create_app():
    app = Flask(__name__)

    @app.route("/")
    def hello():
        return "<p>Hello, World!</p>"

    return app
  • これをApacheから呼び出せるようにするため以下の内容をmyapp.wsgiファイルとして保存する。
sys.path.insert(0, "/var/www/html/myapp") ## venv環境のパス
from app import create_app
application = create_app()

Apacheディレクティブの修正

  • mod_wsgiをロードさせて使うには、LoadModuleディレクティブにインストールしたmod_wsgiモジュールのパスを記述する必要がある。やり方として、インストールしたモジュールを/etc/httpd/modules/にコピーしてパスを書くか、pip3 show mod_wsgiで確認したロケーションにあるモジュールの絶対パスを記述してあげればよい。
  • 下記のコマンドを実行すると、モジュールのコピーと必要なディレクティブが出力されるので便利。
    • でもなぜかコピーされたモジュールに実行権限がついてないので、別途chmodが必要。
(myenv) mod_wsgi-express install-module
LoadModule wsgi_module "/usr/lib64/httpd/modules/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so"
WSGIPythonHome "/var/www/html/myenv"

chmod a+x /usr/lib64/httpd/modules/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so
  • 上記で確認したLoadModuleWSGIPythonHomeの2行をhttpd.confに追記する。
  • 次にアプリを実行するためのディレクティブを書いていく。
  • 特に指定しない場合、FlaskアプリはApacheの子プロセスで実行されるembededモードで動作する。このモードは推奨されないので、別デーモンとして動かしてあげる必要がある。詳細は、次の公式ページを参照。
  • ディレクティブの書き方は、色々説明を省くと、例えばhttp://www.example.com/myappにアクセスしてアプリを実行したい場合は、以下のようなディレクティブをApacheコンフィグに追記してあげればよい。
    • VirtualHostディレクティブは省略しているので、適当なVirtualHostブロックの中に下記を追記してあげれば良い。
WSGIDaemonProcess myapp user=your_user_name group=wheel threads=5
WSGIScriptAlias /myapp /var/www/html/myenv/myapp.wsgi
<Directory "/var/www/html/myenv">
  WSGIProcessGroup %{GLOBAL}
  WSGIApplicationGroup %{RESOURCE}
  WSGIScriptReloading On
  Require all granted
</Directory>
  • 各ディレクティブの詳細は省略するけど、意味はざっくりと以下の感じ。
    • WSGIDaemonProcess:作成するデーモンプロセスをどのユーザ ・グループで実行するかや、スレッド数を指定している。詳細は、 WSGIDaemonProcess — mod_wsgi 4.9.4 documentationを参照のこと。
    • WSGIScriptAlias:これはAliasディレクティブとほぼ同じ。wsgiファイルを指定してあげるところが違う。
    • WSGIProcessGroup:アプリがどのプロセスグループで実行されるかを指定する。
    • WSGIApplicationGroup:アプリがどのアプリケーショングループに所属するかを設定する。同じグループのアプリは、同じPythonインタプリタで処理が行われる。複数のアプリを実行する場合は、アプリ名を指定して上げれば良い。
    • WSGIScriptReloadingWSGIファイルが変更されたらアプリをリロードするかどうかを設定する。デフォルトでOnなので記述しなくても良い。

以上までの設定をしてhttpdプロセスを起動してあげると無事アプリが起動すると思う。

エラー対応

mod_wsgiのインストール時に色々とエラーが出た場合の対処。

$ python3 -m pip install mod_wsgi
 RuntimeError: The 'apxs' command appears not to be installed or is not executable. Please check the list of prerequisites in the documentation for this package and install any missing Apache httpd server packages.
  • このエラーが出た場合は、Apacheのヘッダファイルが無いので、httpd-develをインストールしてあげれば良い
src/server/wsgi_python.h:26:10: fatal error: Python.h: No such file or directory
  • このエラーが出た場合は、Pythonのヘッダファイルが必要なのでpython39-develをインストールしてあげる