
Nginx・Gunicorn・Djangoの関係を整理する|サーバーの中の位置づけと設定の考え方
NDシステムズは、日頃の制作で使う技術だけでなく、その周辺の仕組みにも
目を向けて学ぶことを大切にしています。
この記事では、Pythonのフレームワーク「Django」で作ったアプリケーションをVPS(仮想サーバー)で公開するときの構成を、学習用にまとめた資料をもとにご紹介します。代表者の坂本がDjangoを使って開発した経験を土台に、アプリケーションの外側で何が起きているのかを学び直しました。
この分野には、よく目にするものの、意味を説明しようとすると言葉に詰まる用語が多くあります。この記事では、そうした用語も一つずつ、できるだけイラストを交えて整理します。
サーバーは、6つの層でできている
最初に整理したのは、サーバー全体を層に分けて見る考え方です。下から、ハードウェア、仮想化、OS、ミドルウェア、実行環境、アプリケーションの順に積み重なっています。

VPSでは、OSの導入から上を管理者の権限で自由に設定できます。その分、OSの更新や守りも利用者の責任になります。不具合が起きたときも、まずどの層の話かを切り分けることが出発点になります。
ハードウェアと仮想化の用語
SSD:データを保存する記憶装置です。以前のハードディスクと比べて読み書きが速く、OSやデータベースのファイルはここに保存されます
ハイパーバイザー:1台の物理サーバーのCPU・メモリ・SSDを仕切り、複数の仮想マシンに割り当てる仕組みです
仮想マシン:ハイパーバイザーによって仕切られた、仮想のコンピューターです。利用者からは、独立した1台のサーバーに見えます。VPSは、この仮想マシンを1台分借りるサービスです

OSと実行環境の用語
OS:CPU・メモリ・ファイル・通信を管理し、プログラムに割り当てる基本のソフトウェアです。サーバーでは、Linuxの一種であるUbuntuが多く使われています
systemd:Ubuntuで、プログラムの起動・停止・再起動を管理する仕組みです。サーバーの起動時にNginxなどを開始し、止まったときは自動で再起動します

ファイアウォール:外部からの通信を、決めた扉(後述のポート)以外で遮断する仕組みです
ライブラリ:よく使う機能をまとめた、プログラムの部品です。Django自体も、Pythonのライブラリの一つです
仮想環境(venv):アプリケーションごとに、ライブラリの置き場所を分けるPythonの仕組みです。アプリAとアプリBで必要なDjangoの版が違っても、互いに影響しません

「ミドルウェア」という言葉の2つの意味
学ぶ中で混乱しやすかったのが、「ミドルウェア」という言葉です。サーバーの層としてのミドルウェアは、NginxやPostgreSQLのような、OSとアプリケーションの間で共通の仕事を担う独立したプログラムを指します。一方、Djangoの中のミドルウェアは、すべての依頼の前後に実行される処理(ログインの確認やCSRFの対策など)を指し、同じ言葉でも範囲が異なります。
1回の依頼が、Djangoに届くまで
ブラウザからの依頼は、Nginx、Gunicorn、Djangoの順に渡り、必要に応じてPostgreSQLから情報を取り出します。利用者と直接通信するのはNginxに限られ、GunicornとPostgreSQLはサーバーの内部からのみ接続できるように配置します。

Nginxが443番で接続を受け付け、HTTPSの暗号を解く
静的ファイルはNginxが自分で返し、それ以外はGunicornへ転送する
Gunicornの空いているワーカーが、WSGIという規格でDjangoを呼び出す
DjangoがPostgreSQLから情報を取り出し、HTMLを生成する
結果がGunicorn、Nginxの順に戻り、ブラウザが画面を表示する
通信の用語
プロセス:実行中のプログラムのことです。Nginx・Gunicorn・PostgreSQLは、それぞれ別のプロセスとして動いています
ポート:1台のサーバーの中で、通信の行き先を区別する番号です。建物の扉の番号のようなもので、HTTPSは443番、HTTPは80番、サーバーを遠隔で操作するSSHは22番、PostgreSQLは5432番が標準です

HTTPS:ブラウザとサーバーの間の通信を暗号化する仕組みです。証明書によって、接続先が本物であることも確認できます
UNIXソケット:同じサーバーの中のプロセスどうしが通信するための窓口です。ファイルとして存在し、外部からは接続できません
WSGI:ウェブサーバーとPythonのアプリケーションをつなぐための、共通の規格です。GunicornとDjangoは、この規格に沿ってやり取りします
SQL:データベースに、情報の取り出しや保存を指示するための言語です
ORM:Pythonのコードから、SQLを自動で組み立てる仕組みです。Djangoでは、SQLを直接書かなくてもデータベースを操作できます

NginxとGunicornの役割分担
NginxとGunicornは、どちらも「サーバー」と呼ばれるため、違いが分かりにくい組み合わせです。資料では、飲食店にたとえて整理しました。
Nginx:客を迎えて注文を受ける受付。接続の受け付け、HTTPS、静的ファイルの返却を担う
Gunicorn:注文を料理人(ワーカー)に割り振る厨房の責任者。Pythonのプログラムを動かす
Django:料理の手順(レシピ)。画面と業務の処理を担う
PostgreSQL:食材の倉庫。受注や顧客などの情報を保存する

ワーカーとは
ワーカーは、依頼を実際に処理するプロセスです。Gunicornを起動すると、まず「マスター」が立ち上がり、マスターが複数のワーカーを起動して見守ります。それぞれのワーカーは、Djangoを読み込んだ独立したPythonのプログラムです。

標準の同期のワーカーは、1つの依頼を最後まで処理してから次の依頼を受けます。ワーカー1つが数十から百数十MBのメモリを使うため、小さなVPSでは、増やせるワーカーの数はメモリの量で決まります。ワーカーが止まったときは、マスターが代わりのワーカーを起動します。
Gunicornだけで公開しない理由
GunicornもHTTPの依頼を直接受けられますが、公式の説明でも、Nginxのようなプロキシ(依頼を受け取って代わりに転送する中継役)の後ろに置くことが強く推奨されています。

特に大きな理由は、通信の遅い利用者からワーカーを守ること(バッファリング)です。Gunicornだけで受けると、通信が終わるまでワーカーが待たされ、ほかの依頼を処理できなくなります。Nginxが受信と送信を肩代わりし、完了してから渡すことで、ワーカーを業務の処理に集中させられます。
python manage.pyとrunserverの意味
Djangoを学ぶと最初に出てくるのが、「python manage.py runserver」という命令です。毎回入力していても、それぞれの言葉の意味を説明するのは意外に難しいものです。
python:Pythonのプログラムを実行する命令です
manage.py:Djangoのプロジェクトを作ると最初から用意される、操作の入口になるファイルです。後ろに続ける言葉で、さまざまな操作を呼び出します
settings.py:Djangoの設定をまとめたファイルです。データベースの接続先や、静的ファイルの置き場所などを書きます

manage.pyで呼び出す主な命令は、次のとおりです。
runserver:開発用の簡易サーバーを起動します。自分のパソコンで画面を確認するためのもので、多くの依頼を同時に処理する性能や安全の機能はなく、Django自身も本番での利用を想定していません。本番では、runserverの代わりにGunicornがDjangoを動かします
migrate:models.py(データの項目の定義)に合わせて、データベースの表を作成・変更します
collectstatic:各アプリに散らばった静的ファイルを、1か所(STATIC_ROOT)に集めます
check --deploy:本番に必要な安全の設定の不足を、一覧で示します
静的ファイルを、Nginxから配信する理由
静的ファイルとは、CSS・JavaScript・ロゴの画像のように、どの利用者にも同じ内容を返すファイルです。Pythonの処理を通す必要がないため、Pythonを動かさないNginxに任せます。Gunicornで返すと、画像1枚のためにワーカーが1つ占有され、画面の処理に回るワーカーが不足します。

runserverで開発しているときは、Djangoが静的ファイルを探して返してくれます。一方、本番(DEBUG = False)では、collectstaticでファイルをSTATIC_ROOTに集め、Nginxにその場所を伝えます。本番でCSSが表示されない原因の多くは、collectstaticの未実行か、Nginxの設定の場所の誤りです。
Djangoには、ファイル名に内容の指紋を付ける機能(ManifestStaticFilesStorage)もあります。style.cssがstyle.3f2a91c.cssのような名前で保存され、内容を変えると名前も変わります。そのため、キャッシュ(一度取得したファイルをブラウザが保存し、次回に再利用する仕組み)の期間を長くしても、更新が確実に反映されます。
PostgreSQLと、メモリの配分
PostgreSQLは、Djangoとは別のプロセスとして動くデータベースのサーバーで、接続ごとに専用のプロセスを起動します。メモリ2GBの小さなVPSでは、OSに約300MB、PostgreSQLに約500MB、Gunicornのワーカー3つに1つあたり約60〜150MBという配分が一つの目安です。数値はアプリケーションにより大きく異なるため、実際の使用量を確認してワーカーの数を決めます。
設定で重視する順序
資料の中で最も大切だと感じたのは、設定で重視する順序です。

安全:公開するポートを絞り、管理者の権限で動くものを減らし、更新を続ける
復旧できること:バックアップをサーバーの外に置き、復元の手順を訓練しておく
安定:異常が起きても自動で再開し、停止に早く気づく
性能:上の3つが整ったうえで、ワーカーの数やキャッシュを調整する
性能の不足は後から補えますが、失ったデータは戻りません。なお、動作中のデータベースのファイルを複写しても正しいバックアップにはならないため、pg_dump(PostgreSQLのバックアップの命令)のような専用の方法で取得します。
具体的には、SSHを鍵による認証に限る、GunicornとPostgreSQLを外部に公開しない、DjangoのDEBUG(誤りの詳細を画面に表示する開発用の設定)をFalseにする、といった設定を先に整えます。DEBUGがTrueのままでは、誤りの画面に設定やコードの内容が表示されてしまいます。
症状から、どの層の問題かを判断する
画面に出る誤りの番号から、どの層を確認すればよいかも整理しました。

502 Bad Gateway:Gunicornが停止しているか、Nginxとの接続先が一致していない
504 Gateway Timeout:Djangoの処理が、Nginxの待ち時間を超えた
400 Bad Request:ホスト名が、DjangoのALLOWED_HOSTS(受け付けるドメインの一覧)にない
CSSや画像が表示されない:静的ファイルの場所を、Nginxが把握していない
ログイン後にhttpへ戻される:HTTPSであることが、Djangoに伝わっていない
502と504はNginxが返す画面ですが、原因の多くはGunicornとDjangoの側にあります。まずNginxのerror.log(誤りの記録)で、転送先との間で起きたことを確認します。
学んで分かったこと
層で考える:障害も守りも、どの層の話かを最初に切り分ける
得意な仕事を分担する:Nginxは入口と静的ファイル、GunicornはPythonの実行、Djangoは業務の処理、PostgreSQLはデータの保存を担う
外に開くのは入口に限る:GunicornとPostgreSQLは、サーバーの内部に閉じる
安全と復旧を先に:更新・権限・バックアップ・監視を整えてから、性能を調整する
使う言語やサービスが違っても、この考え方は共通しています。用語の意味を一つずつ確認していくと、それぞれの設定がなぜ必要なのかも見えてきました。NDシステムズは、これからも制作で直接使う技術に限らず、幅広く学んだことを発信していきます。
免責事項
この記事は、筆者が個人として調べたことや経験をもとに、執筆時点の内容をまとめたものです。法律・税務・会計・投資などの専門家による助言ではありません。分かりやすさを優先し、細かい条件や例外を省いている場合があります。
制度、製品の仕様、料金、施設の営業時間などは変わることがあります。実際の判断や手続きにあたっては、出典や公式の情報で最新の内容を確認し、必要に応じて専門家や窓口にご相談ください。この記事の内容を利用して生じた損害については、責任を負いかねます。
NDシステムズのサービスについて
NDシステムズは、月額制のホームページ制作を中心に、事業のデジタル化を支援しています。ホームページ制作は公開後の更新と改善まで月額で続けてお引き受けし、独自システム開発は1つの業務に絞ったシステムを承ります。初回の無料相談(オンライン・30分)は、お問い合わせのフォームまたはメールで承ります。