python manage.py runserverやflask runのまま本番公開していないだろうか── これはやってはいけない.開発サーバーは本番の負荷・セキュリティに耐えるようには作られていない.
Pythonアプリの正しい本番デプロイには,GunicornやuWSGI(ASGIならUvicorn)といったアプリケーションサーバーが必要だ.これらがアプリを並行処理可能な形で動かし,前段のNginxが受け口になる.
この記事は,Django/Flask/FastAPIをVPSで公開する個人開発者に向けている.なぜ開発サーバーではダメか,WSGI/ASGIとは何か,ワーカー数の決め方,Nginx連携,systemd常駐までを実践的に解説する.
読み終えたとき,あなたはPythonアプリを本番品質のアプリケーションサーバーで,正しく安全に公開できるようになっている.
なぜ開発サーバーを本番で使ってはいけないか
DjangoやFlaskの開発サーバー(runserver等)は,開発の利便性のために作られており,本番用ではない.公式ドキュメントも明確に「本番で使うな」と警告している.
理由は,(1)同時リクエストをほとんど捌けない (2)セキュリティ面の堅牢性がない (3)安定性・パフォーマンスが本番水準でないからだ.アクセスが来れば即座に詰まる.
正しくは,本番用のアプリケーションサーバー(Gunicorn/uWSGI/Uvicorn)でアプリを動かす.これらは複数ワーカーで並行処理し,本番の負荷に耐えるよう設計されている.
そして前段にNginxを置き,静的ファイル配信・HTTPS終端・バッファリングを担わせる.この「Nginx+アプリケーションサーバー」が,Python本番デプロイの標準構成だ.
WSGI/ASGIとは ― アプリとサーバーの接続規約
Pythonには,WebアプリとサーバーをつなぐWSGI/ASGIという規約がある.これを理解すると,どのサーバーを選ぶべきかが分かる.
| 規約 | 対象 | サーバー例 |
|---|---|---|
| WSGI | 同期(従来型) | Gunicorn, uWSGI |
| ASGI | 非同期(async対応) | Uvicorn, Hypercorn |
Django(従来)・Flaskは同期(WSGI)なのでGunicorn/uWSGIを,FastAPIや非同期対応のDjango/Flaskは非同期(ASGI)なのでUvicornを使う.「自分のフレームワークが同期か非同期か」で選ぶサーバーが決まる,と覚えればよい.
Gunicornで動かす ― 最も標準的な選択
WSGIアプリ(Django/Flask)の本番デプロイで最も標準的なのがGunicornだ.複数のワーカープロセスでリクエストを並行処理する.
Gunicornでの起動
pip install gunicorn
# Flask(app.py の app)
gunicorn --workers 3 --bind 127.0.0.1:8000 app:app
# Django
gunicorn --workers 3 --bind 127.0.0.1:8000 myproject.wsgi:application--bind 127.0.0.1:8000でlocalhostにバインドするのが重要だ(外部公開はNginxが担う).Gunicornを直接インターネットに晒さず,前段のNginx経由でアクセスさせる.--workersで並行処理数を指定する(次節で詳説).
ワーカー数の決め方 ― CPUコアから逆算
ワーカー数は性能を左右する重要な設定だ.一般的な目安は「(CPUコア数 × 2) + 1」とされる.多すぎるとメモリを食い,少なすぎると並行性が出ない.
ワーカー数の指定
# 2コアVPSなら (2*2)+1 = 5 が目安
gunicorn --workers 5 --bind 127.0.0.1:8000 app:app
# 非同期ワーカー(I/O待ちが多いアプリ)
gunicorn -k uvicorn.workers.UvicornWorker --workers 3 app:app「(コア数×2)+1」は出発点であり,アプリの特性で調整する.CPUを使う処理が多いならコア数寄りに,I/O待ち(DB・API)が多いなら非同期ワーカーやワーカー数増を検討する.メモリ使用量も見ながら,VPSのメモリに収まる範囲で決める.多コアVPSほど並行性を上げられる.
FastAPI/非同期アプリ ― Uvicornを使う
FastAPIのような非同期(ASGI)アプリは,Uvicornで動かす.本番ではGunicornでUvicornワーカーを管理する構成が定番だ(プロセス管理はGunicorn,非同期処理はUvicorn).
FastAPIの本番起動
pip install uvicorn gunicorn
# GunicornでUvicornワーカーを管理(本番推奨)
gunicorn main:app
-k uvicorn.workers.UvicornWorker
--workers 4 --bind 127.0.0.1:8000この構成は,Gunicornの堅牢なプロセス管理と,Uvicornの非同期性能を両立する.FastAPIのドキュメントでも推奨されるパターンだ.単体のUvicornでも動くが,本番のプロセス管理(ワーカー再起動等)はGunicorn経由が安心だ.
Nginxとの連携 ― 静的配信とHTTPS終端
前段のNginxが,HTTPS終端・静的ファイル配信・バッファリングを担い,動的リクエストだけをアプリケーションサーバーに渡す(リバースプロキシ記事参照).
NginxからGunicornへ振り分け
server {
listen 443 ssl;
server_name example.com;
# 静的ファイルはNginxが直接配信
location /static/ { alias /var/www/app/static/; }
# 動的リクエストはGunicornへ
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}静的ファイル(CSS/JS/画像)はNginxが直接配信し,アプリケーションサーバーには動的リクエストだけを渡すのが鉄則だ.Pythonアプリに静的配信をさせるのは非効率で,Nginxの方が圧倒的に速い.X-Forwarded-Protoを渡さないとアプリがHTTPS判定を誤る点も重要だ(リバースプロキシ記事参照).
systemdで常駐させる ― 本番の常駐運用
Gunicorn/Uvicornは,systemdサービスとして常駐させるのが本番の作法だ(systemdの記事参照).これでOS再起動後も自動で立ち上がり,クラッシュからも復帰する.
/etc/systemd/system/myapp.service
[Unit]
Description=Gunicorn for myapp
After=network.target
[Service]
User=deploy
WorkingDirectory=/home/deploy/app
EnvironmentFile=/home/deploy/app/.env
ExecStart=/home/deploy/app/venv/bin/gunicorn
--workers 3 --bind 127.0.0.1:8000 app:app
Restart=always
[Install]
WantedBy=multi-user.target仮想環境(venv)のgunicornを絶対パスで指定するのがポイントだ(systemdはPATHを継承しない).これでGunicornがsystemd管理下で常駐し,OS再起動・クラッシュから自動復帰する.「Nginx+Gunicorn(systemd常駐)+アプリ」が,Python本番デプロイの完成形だ.
補論:Pythonの並行処理は「マルチコアVPS」で活きる
Gunicorn/uWSGIのワーカーによる並行処理は,CPUコアとメモリの余裕があって初めて性能が出る.ワーカーを増やすほどメモリを消費するため,コア数とメモリのバランスが重要だ.
高速NVMe・50種類以上のOSテンプレートに対応した国内VPS─シン・VPS─ は複数vCPUとスケールアップ可能なメモリを備え,「(コア数×2)+1」のワーカーをメモリに余裕を持って動かせる.NVMe SSDで起動やデプロイも速く,スナップショットで設定変更も安全に試せる.Pythonアプリの本番基盤として堅実だ.
公開には独自ドメイン+HTTPSが要る.取り扱い400種類以上のドメイン取得サービス─ムームードメイン─ でドメインを取得し,Nginxで終端してGunicornのアプリに振り分ければ,本番品質のPythonサービスが完成する.
よくある質問(FAQ)
Q1.なぜrunserverやflask runではダメ?
開発用で本番の負荷・セキュリティに耐えないからだ.同時リクエストをほぼ捌けず,公式も本番利用を禁じている.Gunicorn/uWSGI/Uvicornを使う.
Q2.GunicornとuWSGIどちら?
Gunicornの方がシンプルで広く使われる.迷ったらGunicornでよい.uWSGIは高機能だが設定が複雑だ.FastAPI等の非同期はUvicorn(GunicornでUvicornワーカーを管理)を使う.
Q3.ワーカー数はいくつにする?
目安は「(CPUコア数×2)+1」.CPU負荷が高いならコア数寄り,I/O待ちが多いなら非同期ワーカーや増加を検討.メモリに収まる範囲で実測調整する.
Q4.静的ファイルはどこで配信する?
Nginxが直接配信する.Pythonアプリに静的配信をさせるのは非効率だ.Nginxで/static/を直接返し,動的リクエストだけアプリケーションサーバーに渡す.
Q5.FastAPIの本番構成は?
GunicornでUvicornワーカーを管理する構成が推奨だ(-k uvicorn.workers.UvicornWorker).Gunicornのプロセス管理とUvicornの非同期性能を両立できる.
Q6.HTTPS判定がおかしい
NginxからX-Forwarded-Protoヘッダを渡すこと.これが無いとアプリが「HTTPアクセス」と誤認し,リダイレクトループ等を起こす.フレームワーク側でこのヘッダを信頼する設定も必要な場合がある.
まとめ ― 「Nginx+アプリケーションサーバー」が正解
Pythonアプリの本番デプロイは,開発サーバーを使わず,Gunicorn/uWSGI(非同期はUvicorn)で動かし,前段のNginxが静的配信とHTTPS終端を担うのが正解だ.systemdで常駐させれば完成する.
今日やるべきことは,本番でrunserverを使っていないか確認し,使っていればGunicornに切り替えること.ワーカー数はまず「(コア数×2)+1」から始める.
正しい構成は安定とセキュリティの土台だ.マルチコアでスナップショットの取れるVPSなら,Python本番運用を安心して組み上げられる.