以前、URL入力からページ表示までを整理してみたという記事を書きました。
その中で「HTTPリクエスト送信 / レスポンス受信」を1つのステップとしてまとめましたが、実はここにはnginxという重要な登場人物が隠れています。
今回はテーマを変えずに、「URLを入力してからページが表示されるまで」の中の、この1ステップだけをさらに深掘りしてみます。
1. おさらい:nginxはどこにいるのか
前回の記事では、ブラウザとサーバーの間で1回のやり取りが行われるようなイメージで説明しました。しかし実際の本番環境では、ブラウザから見て1回のやり取りに見えても、サーバー側は2段構成になっていることがほとんどです。
ブラウザ → nginx → アプリケーションサーバー(WordPress/PHP-FPM、Honoなど)
ブラウザからのリクエストは、アプリケーションサーバーに直接届くのではなく、まずnginxが受け取り、そこから適切なアプリケーションサーバーに転送されます。
💭 たとえるなら...
レストランで、お客さんの注文を直接キッチンが聞くのではなく、まずホールスタッフ(nginx)が注文を受けて、キッチン(アプリケーションサーバー)に伝える、という役割分担に近いです。お客さんはホールスタッフとしかやり取りしませんが、実際に料理を作っているのはキッチンです。
2. なぜ直接アプリケーションサーバーに繋がないのか
わざわざnginxを間に挟む理由は、主に3つあります。
- 窓口を1つに絞れる: 外部に公開するポートをnginxだけに限定できるので、アプリケーションサーバーを直接インターネットにさらさずに済みます
- 複数のサーバーに振り分けられる(ロードバランシング): アプリケーションサーバーが複数台ある場合、nginxがリクエストを分散させることができます
- 静的ファイル配信を肩代わりできる: 画像やCSSなどの静的ファイルはnginxが直接返すことで、アプリケーションサーバーの負荷を減らせます
💭 たとえるなら...
オフィスビルの受付が1階に1つだけあるようなものです。各テナント(アプリケーションサーバー)に来客が直接エレベーターで押しかけるのではなく、必ず受付(nginx)を経由することで、案内も管理もしやすくなります。
3. 実際のnginx.confを読んでみる
ここからは、実際に自分が書いたnginxの設定ファイルを見ながら、1つずつ「なぜこの設定が必要なのか」を確認していきます。
題材は、42という学校のInceptionという課題で、Dockerだけを使ってnginx・MariaDB・WordPressの基盤を一から構築するものです。
HTTPへのアクセスを問答無用で切断する
server {
listen 80;
return 444;
}
80番ポート(暗号化されていないHTTP)へのアクセスが来たら、444という特殊なステータスコードを返してすぐに接続を切っています。444はnginx独自の「レスポンスを返さずに接続を切断する」というコードです。
前回の記事の「TLSハンドシェイク」のところで、HTTPSは通信を暗号化する仕組みだと説明しましたが、この設定はまさに「暗号化されていない通信は一切受け付けない」という意思表示です。
HTTPSの窓口を作る
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mito.42.fr;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
...
}
443番ポート(HTTPS)だけを受け付け、ssl_certificateで指定した証明書を使って暗号化を行います。前回の記事で説明した「TLSハンドシェイク」のステップが、まさにこの数行で処理されています。
💭 たとえるなら...
前回の記事で「鍵付き封筒を用意する」という例えを使いましたが、その封筒(証明書と鍵)を実際に保管し、使う場所がここです。
PHPだけをアプリケーションサーバーに転送する
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
ここが一番の核心部分です。.phpで終わるリクエストだけを、fastcgi_pass wordpress:9000という行で、WordPressが動いているコンテナに転送しています。
ポイントは、これが単純な「HTTPでの転送」ではなく、FastCGIという別のプロトコルだということです。nginx自体はPHPのコードを実行する機能を持っていないので、「PHPを実行できる別のプロセス(PHP-FPM)に、実行を丸ごと委任している」というのが実態です。
💭 たとえるなら...
ホールスタッフ(nginx)が「イタリア料理の注文」をそのままイタリアン担当のシェフ(PHP-FPM)に渡すようなものです。ホールスタッフ自身は調理をしません。あくまで「どの担当に渡すか」を判断して受け渡すだけの役割です。
4. 自己署名証明書について少し補足
先ほどのssl_certificateで指定していた証明書は、実は以下のコマンドで自分で発行したものです。
RUN openssl req -newkey rsa:2048 -x509 -sha256 -days 365 -nodes \
-out /etc/nginx/ssl/nginx.crt \
-keyout /etc/nginx/ssl/nginx.key \
-subj "/C=FI/ST=Helsinki/L=Helsinki/O=42/OU=Hive/CN=mito.42.fr"
前回の記事で、TLSハンドシェイクでは「この証明書は本当にそのお店から発行されたものか」を確認すると説明しましたが、これは本来、実在の第三者機関(認証局/CA)が発行するものです。今回は学習用の環境なので、自分自身で証明書を発行する自己署名証明書を使っています。ブラウザで自己署名証明書のサイトにアクセスすると警告が出るのは、この「第三者機関のお墨付きがない」ことが理由です。
まとめ
- ブラウザとアプリケーションサーバーの間には、実際にはnginxのようなリバースプロキシが挟まっていることが多い
- nginxは、窓口の一本化・負荷分散・静的ファイル配信などの役割を担っている
-
listen 80; return 444;のように、HTTPを拒否してHTTPSを強制する設定ができる - PHPのようにnginx自身が実行できない処理は、FastCGIなどの別プロトコルでアプリケーションサーバーに委任している
- 「ブラウザが受け取るレスポンス」は、アプリケーションサーバーが返したものそのままとは限らない
前回の記事と合わせて読むと、「URLを入力してからページが表示されるまで」の裏側を、ネットワークからレンダリングまで一通り説明できるようになったと思います。
