始めに
Ubuntu上のApache2でmod_wsgiを利用してFlaskのwebアプリを動かす方法を記述する。
Pythonはpyenvとvenvを利用した仮想環境を使う。
上記の構成でWEBサーバーを構築しようとしたところ、多くのエラーに見舞われ、たくさんの記事を読んだり、一つひとつ設定を試すことになったため、自分が利用した情報とわかったことをまとめた。
前提条件
Apacheの設定、Flaskのプログラム作成やpyenvとvenvによる環境構築は終わっているものとする。
python app.py
などでローカルサーバーを動かせる状態にあればよい。
筆者の環境
OS : Ubuntu 22.04 (VPS上)
Pyhton : 3.11.6 (pyenv+venv)
ディレクトリ構成(抜粋)
root/
├ etc/
└ apache2/
├ sites-available/
└ example.com.conf
└ example.com-le-ssl.conf
└ sites-enabled/
└ example.com.conf
└ example.com-le-ssl.conf
└ var/
└ www/
└ example.com/
├ html/
└ wsgi-bin/
├ app.py
├ index.wsgi
└ venv/
├ bin/
└ lib/
└ pyhton3.11/
└ site-packages/
└ mod_wsgi/
└ server/
└ mod_wsgi-py311.cpython-311-x86_64-linux-gnu.so
mod_wsgiのインストール
Apacheでwsgiを使うためのモジュールmod_wsgiをインストールする。
今回はデーモンモードを使う。(違いについてはこの記事が詳しい。)
本番環境で使用するvenvの仮想環境に入った上で、下記コマンドを実行する。
pip install mod-wsgi
この時点でapache2-dev を apt などでインストールしてないとエラーになる。
(インストール方法:apt install apache2-dev
)
mod_wsgiをaptよりインストールする方法もあるが、pyenvとvenv を使う場合はapt install libapache2-mod-wsgi-py3
でインストールすると、ライブラリの読み込み時などにエラーが発生した。
この記事によると、aptでのインストール時に使うPythonとアプリを動かすPythonのバージョンが異なるため、エラーになるらしい。
Apache の設定
/etc/apache2/sites-available/
あたりにあるVirtualHostの設定ファイルを編集する。
<VirtualHost *:80>
ServerName example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/example.com/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# ここから記入
LoadModule wsgi_module /var/www/example.com/wsgi-bin/venv/lib/python3.11/site-packages/mod_wsgi/server/mod_wsgi-py311.cpython-311-x86_64-linux-gnu.so
WSGIDaemonProcess app user=www-data group=www-data threads=5 python-home=/var/www/example.com/wsgi-bin/venv python-path=/var/www/example.com/wsgi-bin/venv/lib/python3.11/site-packages
WSGIScriptAlias / /var/www/example.com/wsgi-bin/index.wsgi
<Directory "/var/www/example.com/wsgi-bin/">
WSGIProcessGroup app
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Order allow,deny
Allow from all
#.htaccessの有効化(無くてもよい)
AllowOverride All
</Directory>
# ここまで記入
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
LoadModule
LoadModuleで、venvの中の/lib/python3.11/site-packages/mod_wsgi/server/mod_wsgi-py311.cpython-311-x86_64-linux-gnu.so
を指定することで、pipによってインストールしたmod_wsgiを読み込んでいる。
WSGIDaemonProcess
WSGIDaemonProcessとWSGIProcessGroupのapp
の部分は任意の名前でいいが、同じにしないといけない。
また、VirtualHostなどで複数のWSGIDaemonを動かす場合は、互いに重複しないようにする。
userとgroupはpythonを実行するユーザーとグループの名前にする。(www-dataはApacheなどが利用するもの)
python-homeはvenvのディレクトリを指定する。
venv/bin/
ではなくvenv/
を指定しないといけないので注意。
python-pathにはライブラリのあるディレクトリを指定する。
ここに書く代わりに、wsgiファイルのsys.pathに書く方法もある。(index.wsgiのコメントアウト部参照)
SSLを使う場合は、同様の内容をexample.com-le-ssl.confなどに書くと思うが、SSLの方にはWSGIDaemonProcessを書いてはいけない。
Let's encryptなどでは自動でコピーされるので、この部分だけ消す必要がある。
また、LoadModuleもSSL用のファイルでは不要である。
WSGIScriptAlias
cgiで使うAliasと同じ書き方をする。
今回はexample.com
へアクセスすればFlaskに繋がるようにしている。
WSGIScriptAlias /wsgi/ /var/www/example.com/wsgi-bin/index.wsgi
と書けば、example.com/wsgi/
にアクセスすることでFlaskへ繋がるようにできる。
詳細はこの記事が詳しい。
wsgiファイル
import sys
sys.path.insert(0, "/var/www/example.com/wsgi-bin")
# sys.path.insert(0, "/var/www/example.com/wsgi-bin/venv/lib/python3.11/site-packages")
from app import app as application
sys.path.insertでpythonプログラムが置かれているディレクトリを指定し、importできるようにする。
コメントアウトしている部分は、ライブラリのディレクトリをwsgiファイルで指定する場合である。
最後に
これでsystemctl restart apache2.service
をすれば完了である。
mod_wsgiをデーモンモードで動かしているため、Flaskのプログラムを更新したらApache2をリスタートしなくても変更が反映されるという情報を得たが、自分の環境では再現できなかった。
参考にさせていただいたサイト