PythonでWebアプリを作ってみたいと思っても、最初は「Pythonを入れた後に何をすればよいのか」「Apacheだけでは動かないのか」「FlaskとGunicornは何が違うのか」と迷いやすいものです。
この記事では、Rocky Linux上にPythonの実行環境を用意し、Flaskで作ったWebアプリをApache経由で公開するまでを、初めて学ぶ人向けに説明します。例として使うホスト名と設置先は次のとおりです。
ホスト名:python.example.com
設置先:/var/www/html/python.example.com実際に試す場合は、python.example.comを自分のドメインへ読み替えてください。
- PythonとPHPではWebアプリの動かし方が少し違う
- Flaskを選ぶ理由
- 1.Rocky Linuxを更新する
- 2.Pythonとpipをインストールする
- 3.Webアプリ用ディレクトリを作る
- 4.Pythonの仮想環境を作る
- 5.pipを更新してFlaskとGunicornを入れる
- 6.最小のFlaskアプリを作る
- 7.開発用サーバーで確認する
- 8.Gunicornで起動する
- 9.Apacheでpython.example.comだけを転送する
- 10.Apacheの設定を確認して反映する
- 11.本番ではGunicornをsystemdへ登録する
- 12.サービスを登録して起動する
- 13.プログラム更新後の反映とログ確認
- よくあるトラブル
- まとめ
PythonとPHPではWebアプリの動かし方が少し違う
PHPはApacheがPHPファイルを直接読み込み、処理結果を返す構成がよく使われます。一方、PythonのWebアプリでは、ApacheがPythonファイルを直接実行するのではなく、Gunicornというアプリケーションサーバーへアクセスを転送する構成が一般的です。
ブラウザ
↓
Apache
↓
Gunicorn
↓
Flaskで作ったPythonアプリそれぞれの役割を簡単に整理すると、FlaskはWebアプリを作るためのフレームワーク、Gunicornは作成したアプリを常時動かすサーバー、ApacheはインターネットからのHTTP・HTTPSアクセスを受け付ける入口です。
Flaskを選ぶ理由
PythonにはDjango、Flask、FastAPIなどのWebフレームワークがあります。初めて小さなWebアプリを作る場合は、構成が単純で必要な機能を少しずつ追加できるFlaskが分かりやすいでしょう。
- Flask:小規模なWebサイト、学習、簡単な業務アプリ向け
- Django:ログインや管理画面を含む大きめのサービス向け
- FastAPI:スマートフォンアプリや外部サービス向けのAPI開発に向く
今回はFlaskを使います。
1.Rocky Linuxを更新する
sudo dnf update -ysudoは管理者権限でコマンドを実行する指定です。dnfはRocky Linuxでソフトウェアを管理する仕組み、updateはインストール済みパッケージを更新する操作です。-yを付けると、途中の確認へ自動的にyesと回答します。
本番サーバーでは更新による影響がないか確認してから実行してください。
2.Pythonとpipをインストールする
sudo dnf install -y python3 python3-pipinstallはパッケージのインストール、python3はPython本体、python3-pipはPython用パッケージ管理ツールです。pipを使うことでFlaskやGunicornを追加できます。
インストール後にバージョンを確認します。
python3 --version
pip3 --version--versionはインストールされているバージョンを表示する指定です。バージョン番号が表示されれば、Pythonを実行できる状態です。
3.Webアプリ用ディレクトリを作る
sudo mkdir -p /var/www/html/python.example.com
sudo chown -R rocky:rocky /var/www/html/python.example.com
cd /var/www/html/python.example.commkdirはディレクトリを作るコマンドです。-pを付けると、途中のディレクトリが存在しない場合もまとめて作成します。
chownは所有者を変更するコマンドです。-Rは内部のファイルやディレクトリにも再帰的に設定する指定です。ここではRocky Linuxへログインしているユーザー名をrockyとしています。別のユーザーを使っている場合は読み替えてください。
cdは作業するディレクトリを移動するコマンドです。
4.Pythonの仮想環境を作る
python3 -m venv venvpython3でPython 3を起動し、-m venvで仮想環境を作る標準機能を呼び出しています。最後のvenvは作成するディレクトリ名です。
仮想環境とは、Webアプリ専用のPython環境です。OS全体へFlaskなどを直接インストールせず、アプリごとに使用するパッケージとバージョンを分けられます。
続いて仮想環境を有効にします。
source venv/bin/activatesourceは指定した設定ファイルを現在のシェルへ読み込むコマンドです。実行後、プロンプトの先頭に(venv)と表示されれば有効になっています。
仮想環境を終了するときは次を実行します。
deactivateSSHで再ログインした後は仮想環境が解除されていますが、作り直す必要はありません。アプリのディレクトリへ移動し、再びsource venv/bin/activateを実行します。
5.pipを更新してFlaskとGunicornを入れる
python -m pip install --upgrade pip
pip install flask gunicornpython -m pipは、現在有効になっているPython環境のpipを実行する書き方です。installはインストール、--upgradeは既に入っているパッケージを新しいバージョンへ更新する指定です。
2行目ではFlaskとGunicornを仮想環境内へインストールしています。
flask:URLとPythonの処理を結び付け、Web画面を作るフレームワークgunicorn:Flaskアプリを本番サーバーで動かすためのWSGIサーバー
6.最小のFlaskアプリを作る
/var/www/html/python.example.com/app.pyを次の内容で作成します。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Python Webアプリが動いています"
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000)from flask import FlaskはFlask本体を読み込みます。app = Flask(__name__)はWebアプリを作成する処理です。
@app.route("/")は、トップページのURLへアクセスされたときに、その直後の関数を実行する指定です。returnでブラウザへ返す内容を指定しています。
最後のapp.run()は、app.pyを直接実行した場合に127.0.0.1の8000番ポートで開発用サーバーを起動する処理です。127.0.0.1は同じサーバー内部からだけ接続できるアドレスです。
7.開発用サーバーで確認する
cd /var/www/html/python.example.com
source venv/bin/activate
python app.py別のSSH接続から次を実行します。
curl http://127.0.0.1:8000/curlはコマンド上からHTTPアクセスを行うツールです。「Python Webアプリが動いています」と返れば、Flaskアプリは正常に動いています。
開発用サーバーは確認には便利ですが、本番公開を目的としたものではありません。本番ではGunicornを使います。
8.Gunicornで起動する
gunicorn --bind 127.0.0.1:8000 app:appgunicornはアプリケーションサーバーを起動するコマンドです。--bind 127.0.0.1:8000は、同じサーバー内部の8000番ポートで待ち受ける指定です。
最後のapp:appは、コロンの左側がファイル名app.py、右側がファイル内で作成したapp変数を示します。
すでに8000番ポートが使用されている場合は「Address already in use」と表示されます。使用中のプロセスは次のコマンドで確認できます。
sudo ss -lntp | grep :8000ssは通信ポートの使用状況を調べるコマンド、-lntpは待ち受け中のTCPポートとプロセスを数値表示する指定です。grep :8000で8000番を含む行だけに絞っています。
9.Apacheでpython.example.comだけを転送する
Rocky LinuxではApacheのサービス名とパッケージ名はhttpdです。
sudo dnf install -y httpd
sudo systemctl enable --now httpdsystemctlはサービスを管理するコマンドです。enableはOS起動時の自動起動を有効にし、--nowは自動起動の設定と同時に、その場でサービスも起動します。
/etc/httpd/conf.d/python.example.com.confを作り、次の設定を記載します。
<VirtualHost *:80>
ServerName python.example.com
ErrorLog /var/log/httpd/python.example.com-error.log
CustomLog /var/log/httpd/python.example.com-access.log combined
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
</VirtualHost>VirtualHost *:80はHTTPの80番ポート用設定、ServerNameは対象のホスト名です。ProxyPassをこのVirtualHostの中へ記載することで、python.example.comへのアクセスだけがGunicornへ転送されます。他のホストには影響しません。
ProxyPreserveHost Onは、ブラウザから送られたホスト名を転送先へ引き継ぎます。ProxyPassはApacheからGunicornへ転送する設定、ProxyPassReverseはGunicornから返された応答ヘッダーを外部公開用に調整する設定です。
この構成ではApacheがファイルを直接表示しないため、基本的にDocumentRootは必要ありません。ページの内容はFlaskが返します。
10.Apacheの設定を確認して反映する
sudo apachectl configtest
sudo systemctl reload httpdapachectl configtestはApache設定の文法確認です。「Syntax OK」と表示されたことを確認してから反映します。
reloadはサービスを停止せずに設定を読み直す操作です。設定に誤りがある状態でいきなり再起動するより、安全に確認できます。
Rocky LinuxでSELinuxが有効な場合は、ApacheからGunicornへのネットワーク接続を許可します。
sudo setsebool -P httpd_can_network_connect 1setseboolはSELinuxの許可項目を変更するコマンドです。-Pを付けると再起動後も設定が維持されます。実際に転送するホストはApacheのVirtualHost設定で指定したpython.example.comだけです。
11.本番ではGunicornをsystemdへ登録する
次のようなコマンドでGunicornをバックグラウンド起動することもできます。
gunicorn --bind 127.0.0.1:8000 --daemon app:appただし、手動起動ではサーバー再起動後に自動で立ち上がらず、異常終了時の復旧やログ確認も面倒です。本番ではsystemdへサービスとして登録します。
サービス名は任意ですが、何の処理か分かりやすいgunicorn-python-example.serviceとします。
sudo vi /etc/systemd/system/gunicorn-python-example.serviceファイルへ次を記載します。
[Unit]
Description=Gunicorn for python.example.com
After=network.target
[Service]
User=rocky
Group=rocky
WorkingDirectory=/var/www/html/python.example.com
ExecStart=/var/www/html/python.example.com/venv/bin/gunicorn --workers 2 --bind 127.0.0.1:8000 app:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetsystemd設定の意味
Description:サービスの説明After=network.target:ネットワークの準備後に起動UserとGroup:Gunicornを実行するLinuxユーザーとグループWorkingDirectory:アプリの作業ディレクトリExecStart:実際に起動するGunicornのコマンド--workers 2:リクエストを処理するワーカープロセスを2つ起動Restart=always:Gunicornが停止した場合に再起動RestartSec=5:再起動まで5秒待機WantedBy=multi-user.target:通常のサーバー起動時に利用するサービスとして登録
仮想環境をsourceで有効にしなくても、ExecStartで仮想環境内のGunicornをフルパス指定しているため、正しい環境が使用されます。
12.サービスを登録して起動する
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn-python-exampledaemon-reloadは新しく作成・変更したsystemd設定を読み直す操作です。設定ファイルを編集しただけではsystemdへ反映されないため、必ず実行します。
enable --nowにより、自動起動の有効化と現在の起動を同時に行います。状態は次で確認できます。
sudo systemctl status gunicorn-python-exampleactive (running)と表示されれば起動しています。
13.プログラム更新後の反映とログ確認
app.pyなどを変更した後は、Gunicornを再起動します。
sudo systemctl restart gunicorn-python-examplePythonプログラムだけを変更した場合、Apacheを再起動する必要はありません。ApacheのVirtualHost設定を変更した場合だけ、構文確認後にApacheをreloadします。
Gunicornのログを直近100件確認する場合は次を実行します。
sudo journalctl -u gunicorn-python-example -n 100リアルタイムで確認する場合は次のとおりです。
sudo journalctl -u gunicorn-python-example -fjournalctlはsystemdが管理するログを表示するコマンドです。-uは対象サービス、-n 100は直近100件、-fは新しいログを継続表示する指定です。
よくあるトラブル
502 Proxy Errorが表示される
ApacheからGunicornへ接続できていない可能性があります。Gunicornの状態、8000番ポート、SELinuxを順番に確認します。
sudo systemctl status gunicorn-python-example
sudo ss -lntp | grep :8000
sudo journalctl -u gunicorn-python-example -n 100Address already in useと表示される
手動で起動したGunicornが残っている、または別のアプリが8000番ポートを使っています。使用中のプロセスを確認し、同じアプリを二重に起動しないようにします。
Apacheの既存サイトまで転送される
ProxyPassがVirtualHostの外側に書かれていないか確認します。python.example.comのVirtualHost内だけに記載すれば、このホストだけが転送対象になります。
まとめ
Pythonのコード自体は比較的読みやすい一方、Webアプリを本番公開するにはFlask、Gunicorn、Apache、systemdの役割を理解する必要があります。最初は登場人物が多く見えますが、それぞれの役割は明確です。
- Flask:Webアプリの処理を作る
- Gunicorn:Flaskアプリを本番環境で動かす
- Apache:外部からのアクセスを受け付けてGunicornへ転送する
- systemd:Gunicornの起動、停止、自動起動、再起動、ログを管理する
まずはトップページに文字を表示する最小アプリを動かし、仕組みを確認してからHTMLテンプレート、MySQL、投稿フォーム、ログイン機能などを追加していくと理解しやすくなります。


コメント