今回はタイトルの通り、Ubuntu20.04 LTS 上で動く Apache2.4 で uWSGI を用いて Python アプリを Web サーバで動かす手順について説明します。
Apache の記事を見ると、CentOS などの RedHat 系の Linux OS の記事はたくさん出てくるのですが Ubuntu でやっているような記事はあまり見当たらず、さらに WSGI の導入に大変苦労したので、記事を執筆しました。
#WSGI とは
WSGI とは、Python アプリと Web サーバをつなぐような役割を持ちます。一応 Flask 単体でも Web サーバ上で動かすことは可能ですが、Development 用と明確に記載されているため WSGI を使用する必要があります。詳しい話は uWSGI入門 や WSGI を使う場合と使わない場合 などの記事を読むと良いでしょう。
有名どころでは mod_wsgi や uWSGI などがありますが、mod_wsgi の開発自体が2016年頃に終了しているせいなのか、自分の設定が悪いのかよくわかりませんが mod_wsgi の導入が上手くいきませんでした。そこで、uWSGI を導入しました。
#環境・バージョン等
$ cat /etc/issue
Ubuntu 20.04.3 LTS \n \l
$ apache2 -v
Server version: Apache/2.4.41 (Ubuntu)
Server built: 2021-09-28T11:00:45
$ python --version
Python 3.8.10
#導入方法
導入方法を説明します。
##uWSGI と Flask をインストール
今回は Flask と uWSGI を用いて行います。pip でインストールしましょう。
$ sudo pip install uwsgi
$ sudo pip install flask
##動かす Python プログラムを作成
今回は run.py というプログラムを作成。
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/')
def hello():
text = "Hello World!"
return jsonify(message = text)
if __name__ == '__main__':
app.run()
これをターミナルで
$ python3 run.py
を実行しましょう。ブラウザで http://localhost:5000/ にアクセスし、画面上に
{"message":"Hello World!"}
と表示されることを確認してください。もしくは、curl
コマンドを用いて実行しても構いません。ターミナルをもう一つ開いて curl
コマンド
$ curl http://localhost:5000/
と実行して
{"message":"Hello World!"}
というレスポンスが帰ってくるかを試し、Python ファイルがきちんと動いていることを確認してください。
きちんと動いていれば、Ctrl + C などのコマンドで Python プログラムを終了させてください。動かなかった場合は、スペルミスなどを注意してやり直してください。
##uWSGIの実行(コマンドで)
以下のようなコマンドを実行してください。module
は Python ファイルの名前(今回は run
)、callable
は Flask のアプリの名前を指定します(今回は app
)。仮想環境(virtualenv など)を使用している場合は、仮想環境のある場所を指定してください( --virtualenv=/home/env/
などを付ける)。
$ uwsgi --http=0.0.0.0:8930 --module=run --callable=app
これで、先ほどのようにブラウザまたは curl コマンドを用いて
{"message":"Hello World!"}
と表示されているかどうかを確かめてください。
##uWSGIの実行(ini ファイルで)
後述するデーモン化(コマンドを入力しなくても Python プログラムが動いている状態にすること)にも関係してくるところなので、ini ファイルでの起動について説明します。一時的なデバッグなら、先述のコマンドで uWSGI を動かせば良いですが、デーモン化するならこちらでやる方がおすすめです。
以下のような ini ファイルを作成します。
[uwsgi]
socket = 127.0.0.1:8930
module = run
callable = app
master = True
chdir = /var/www/html/
; virtualenv = /home/api_env/env/
; logto = /var/log/uwsgi/uwsgi.log
今回は virtualenv
や logto
をコメントアウトにしていますが、必要に応じてこれらの設定を変えてください(後述するデーモン化する際はコンソールに uWSGI のログが出力されないのでコメントアウトを外し、$ mkdir /var/log/uwsgi/
でディレクトリを作成、そこにログを収集していくのがいいかもしれません)。
また、chdir
も ini ファイルの存在するディレクトリに変更してください。
先ほどと同様に、uWSGI を起動します。
$ uwsgi --ini uwsgi.ini
##Web サーバとの連携
localhost 環境ではこのままでOKなのですが、これを Apache などを通して独自ドメインなどで公開する際は Apache の設定が必要です。
まずは、Apache の設定で、ポートフォワードと uWSGI のモジュールを有効化します。/etc/apache2/apache2.conf で以下の2行のコメントアウトを外します。そもそも記述されていない場合は最終行など、適当な場所に書き足してください。
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
http://example.com で公開したい場合、/etc/apache2/sites-available/example.com.conf を編集してパスを通す必要があります。
ProxyPass / uwsgi://127.0.0.1:8930/
ProxyPassReverse / uwsgi://127.0.0.1:8930/
http://example.com/ のディレクトリで実行する場合は上記の設定で良いのですが、http://example.com/api/ などのディレクトリで実行する際は、 ProxyPass や ProxyPassReverse を
ProxyPass /api/ uwsgi://127.0.0.1:8930/
ProxyPassReverse /api/ uwsgi://127.0.0.1:8930/
としてください。うまく行かない場合は、/etc/apache2/apache2.conf に
ProxyPass / uwsgi://127.0.0.1:8930/
ProxyPassReverse / uwsgi://127.0.0.1:8930/
を記述してください。
これらの設定後、再度 uWSGI を実行しながら http://example.com/ にブラウザでアクセスしたり curl
コマンドで
{"message":"Hello World!"}
のレスポンスがあることを確認してください。
#500 Internal Error の場合
500 エラーが発生している場合は、/var/log/uwsgi/uwsgi.log
のログを見て修正してください。
#デーモン化
Ubuntu でのデーモン化について、systemdでプロセス自動再起動 や [Systemd Restart = alwaysは受け入れられません] (https://www.it-swarm-ja.com/ja/systemd/systemd-restart-always%E3%81%AF%E5%8F%97%E3%81%91%E5%85%A5%E3%82%8C%E3%82%89%E3%82%8C%E3%81%BE%E3%81%9B%E3%82%93/962499729/) などの記事を参考にして行いました。
##手順
/etc/systemd/system/ に uwsgi.service ファイルを作成し、以下の内容で書き込みます。
[Unit]
Description = uWSGI
After = syslog.target
[Service]
WorkingDirectory = /var/www/html/
ExecStart = /usr/local/bin/uwsgi --ini /var/www/html/uwsgi.ini
# ここは各自による(後述)
Restart = on-failure
# Restart = always
RestartSec = 3
KillSignal = SIGQUIT
Type = notify
StandardError = syslog
NotifyAccess = all
[Install]
WantedBy = multi-user.target
ExecStart = /usr/local/bin/uwsgi
については(仮想環境を実装している場合は、仮想環境をオンにした状態で)$ which uwsgi
のコマンドを実行し、表示されたディレクトリを指定してください(私は /usr/local/bin/uwsgi でした)。
また、先述のようにログの出力の指定をしてもいいかもしれません。
[Service]
の WorkingDirectory
はご自身の Python ファイルが格納されている場所にしてください。
Restart
は、always
にしてしまうと Python プログラムが途中で切れてしまうために on-failure
としました。
また Restart 間隔がデフォルトのまま(実行間のデフォルトの遅延は100ミリ秒 = 0.1秒)であると、Restart する回数が多すぎると私の環境では怒られたので、RestartSec = 3
にすることによって間隔を広げています。
これで、デーモンのリロードおよび Apache のリロードを行います。
$ sudo systemctl daemon-reload
$ sudo systemctl restart apache2
デーモンを起動させる時は
$ sudo systemctl start uwsgi
などを実行し、逆にデーモン化を止める場合は
$ sudo systemctl stop uwsgi
などを実行してください。
#おわりに
以上の手順で uWSGI を用いて Python プログラムを Web サーバ上で実行することができます。
できない、間違っている場合などがありましたらご指摘お願いします。