- だいぶ前の話で、Flaskアプリ本を読んだ時に作ったアプリはnginxで公開したけど、Apacheだとどうなるのかなと思ってやってみた。Apache + Flaskみたいな単語でググると色々と説明記事がヒットするものの、大体中途半端だったり、古かったりしたので、だいぶ困った。いろいろ調べた結果、mod_wsgiの公式ページを読めばすべて書いてあるし、ここを読んでさえいれば十分だと分かった。
- 今回試した環境は以下の通り。
公式ページ
- mod-wsgi · PyPI
- 概要を知るためにはこのページを読むと良い。簡単にインストール方法と実行方法が書いてある。
- mod_wsgi — mod_wsgi 4.9.4 documentation
はじめに
- 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_wsgi
とpip3 install mod_wsgi
で処理されるランタイムが異なるので、複数バージョンの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
を使う方法。 - 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
- 上記で確認した
LoadModule
とWSGIPythonHome
の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インタプリタで処理が行われる。複数のアプリを実行する場合は、アプリ名を指定して上げれば良い。WSGIScriptReloading
:WSGIファイルが変更されたらアプリをリロードするかどうかを設定する。デフォルトで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
をインストールしてあげる