Nginxって結局何してるの? 自分でサイトを公開して初めて分かった役割

目次
Nginxって結局何してるの?自分でサイトを公開して初めて分かった役割
Next.jsなどで作ったWebアプリを自分でサーバーへ公開しようとすると、かなりの確率で出てくる名前があります。
Nginx。
設定例を見ると、
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}みたいなものが出てきます。
自分もサイトを公開するときにNginxを触っています。
ただ最初の理解はかなり雑で、
「Next.jsの前に置くやつ」
くらいでした。
でも、それだと設定ファイルは書けても、
なぜ前に置くのか。
ブラウザから来たアクセスを何しているのか。
Next.jsとNginxは何が違うのか。
がよく分かりません。
そこで今回は、設定項目を暗記するのではなく、
ブラウザからリクエストが来て、Nginxを通ってアプリへ届き、レスポンスが返るまで
を追いながら、Nginxの役割を整理します。
まず一言でいうと、Nginxは「Webの受付」をやってくれる
かなりざっくり例えるなら、Nginxはビルの受付みたいなものです。
外から来た人が、いきなりビルの奥にある開発室へ突撃するのではなく、
まず受付へ来る。
受付で、
どの会社に用事ですか?
このURLならこちらです。
このファイルなら私が渡します。
アプリへの用事なら奥の3000番へ回します。
と振り分ける。
Nginxのreverse proxyは、これにかなり近い動きをします。
Nginx公式のBeginner's Guideでも、proxy serverはクライアントからリクエストを受け取り、別のサーバーへ渡し、そのレスポンスを受け取ってクライアントへ返すものとして説明されています。
参考: https://nginx.org/en/docs/beginners_guide.html(外部サイト)
たとえばNext.jsが、
127.0.0.1:3000で動いていたとしても、ユーザーに
https://example.com:3000へ直接アクセスしてもらう必要はありません。
外からのアクセスはNginxが80番や443番ポートで受け取り、内部の3000番ポートへ渡せます。
つまり、
インターネット
→ Nginx
→ Next.js
という入口を作れるわけです。

ブラウザからアクセスすると、Nginxまでどう届く?
たとえばブラウザで、
https://example.com/articles/1を開いたとします。
かなり単純化すると、
ドメイン名をDNSでIPアドレスへ解決
→ そのサーバーへHTTPSで接続
→ 443番ポートで待っているNginxへリクエストが届く
という流れになります。
ここでNginxが設定を見ます。
たとえば、
server {
listen 443 ssl;
server_name example.com;
}なら、
listen
listen 443 ssl;は、
443番ポートでHTTPSの接続を待ちます
という設定です。
HTTPなら80、HTTPSなら443がよく使われます。
server_name
server_name example.com;は、
example.com宛てのリクエストは、このserver設定で扱います
という指定です。
Nginx公式Docsでも、同じポートで複数のserverが待ち受ける場合、Hostヘッダーなどをもとにどのserverで処理するかを決定すると説明されています。
参考: https://nginx.org/en/docs/http/request_processing.html(外部サイト)
これがあるので、1台のサーバーで複数のドメインを扱う構成も作れます。
locationは「このURLならどうする?」を決める場所
次に出てくるのが location です。
location / {
proxy_pass http://127.0.0.1:3000;
}この例なら、
このURLに来たリクエストを、127.0.0.1:3000で動いているアプリへ渡して
という意味になります。
Nginxの proxy_pass は、リクエストを別のサーバーへ渡すためのdirectiveです。
参考: https://nginx.org/en/docs/http/ngx_http_proxy_module.html(外部サイト)
ここでポイントなのは、
Nginx自身がNext.jsのページをReactで描画しているわけではない
ことです。
Nginxはリクエストを受け取る。
Next.jsへ渡す。
Next.jsがHTMLなどのレスポンスを返す。
Nginxがそのレスポンスをブラウザへ返す。
という役割分担です。
かなり単純化すると、
ブラウザ
↓
Nginx「このリクエストはNext.js行き」
↓
Next.js :3000
↓
Nginx
↓
ブラウザです。
じゃあNext.jsだけを直接公開しちゃダメなの?
ここで一番気になるのがこれです。
Next.js自体がHTTPサーバーとして動くなら、Nginxいらなくない?
その通りで、NginxがないとNext.jsが動かないわけではありません。
next start でNext.jsのサーバーを起動すれば、それ自体でHTTPリクエストを受けられます。
また、Vercelなどのマネージドな環境を使う場合、自分でNginxを管理しないことも普通です。
ただ、Next.js公式のSelf-Hostingガイドでは、自分でホストする場合、Next.jsサーバーを直接インターネットへ公開するより、Nginxのようなreverse proxyを前段に置くことが推奨されています。
参考: https://nextjs.org/docs/app/guides/self-hosting(外部サイト)
理由として、
malformed requestへの対応
遅い接続への対策
payload size制限
rate limiting
リクエスト処理の一部をアプリから外へ出す
などが挙げられています。
つまり、
Next.jsが動くためにNginxが必要
ではなく、
インターネットとの入口をアプリ本体から分離するためにNginxを置く
と考えた方が近いです。
Nginxは静的ファイルなら自分で返せる
Nginxは、全部をアプリへ丸投げするだけではありません。
静的ファイルを自分で返すこともできます。
Nginx公式のBeginner's Guideにも、ローカルディレクトリから静的コンテンツを配信する例があります。
参考: https://nginx.org/en/docs/beginners_guide.html(外部サイト)
たとえば、
location /images/ {
root /var/www;
}のような構成なら、条件に合うファイルをNginx自身が返せます。
昔から、
静的ファイルはWebサーバー
動的処理はアプリケーションサーバー
という役割分担で使われてきました。
Next.jsの場合は自前の静的アセット処理やキャッシュもあるので、何でもNginxに任せればよいわけではありません。
ただ、
Nginxはただの転送係なのか?
というと、それも違います。
自分でレスポンスを返すことも、別のアプリへリクエストを渡すこともできるWebサーバー
です。
HTTPSの入口もNginxに任せられる
自分でサイトを公開すると、HTTPだけではなくHTTPSも必要になります。
HTTPSではTLS証明書を使って通信を暗号化します。
NginxにはHTTPSを扱うための ngx_http_ssl_module があり、
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}のように証明書と秘密鍵を設定できます。
参考: https://nginx.org/en/docs/http/ngx_http_ssl_module.html(外部サイト)
この構成なら、
ブラウザとのHTTPS通信はNginxが受ける
→ 内部ではNext.jsなどのアプリへproxyする
という形にできます。
このように前段のproxyでTLSを処理することを、一般にTLS terminationと呼びます。
アプリ側がそれぞれ証明書管理をするのではなく、入口側へまとめられるのが分かりやすいところです。
1台のサーバーで複数アプリへ振り分けることもできる
Nginxを理解して「これ便利だな」と思ったのが、入口を一つにまとめられることです。
たとえばサーバー内で、
Next.js → 127.0.0.1:3000
API → 127.0.0.1:8000
別アプリ → 127.0.0.1:4000のように複数アプリが動いていたとします。
Nginx側で、
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
location /api/ {
proxy_pass http://127.0.0.1:8000;
}
}のようにすれば、
https://example.com/ → Next.js
https://example.com/api/ → APIのように振り分けられます。
あるいは server_name を変えて、
example.com → app A
api.example.com → app Bのような構成もできます。
Nginxを「サーバーの前に置くやつ」ではなく、
外から入ってきたHTTPリクエストを、設定に応じて適切な場所へ案内する入口
として見ると、一気に理解しやすくなりました。

Nginxを挟むと、アプリのポートを直接外へ出さなくて済む
たとえばNext.jsが3000番で動いているとします。
Nginxを使う構成なら、外部公開するのは基本的に80/443だけにして、
インターネット
↓ :443
Nginx
↓ :3000
Next.jsという形にできます。
3000番はサーバー内部だけで使う。
これなら、ユーザーがアプリの内部ポートを意識する必要がありません。
また、入口をNginxへ集約することで、
HTTPS
redirect
request size
access control
rate limit
headerの付与
proxy設定
なども前段で扱えます。
もちろん、実際のセキュリティはNginxだけで完結するわけではありません。
ファイアウォール、OS、アプリ、認証、クラウド側の設定なども必要です。
ただ、入口を一か所へ集められるのはかなり大きいです。
Nginxを触るならaccess logとerror logも覚えておきたい
Nginxを「リクエストの受付」と考えると、ログも分かりやすくなります。
access log
誰がどのURLへアクセスして、どんなHTTP statusで返ったかなどを見るためのログです。
Nginx公式Docsでは、access_log でリクエストログを記録できます。
参考: https://nginx.org/en/docs/http/ngx_http_log_module.html(外部サイト)
error log
Nginx自身のエラーや処理上の問題を確認するログです。
たとえば、
Nginxまではアクセスが来ているのか?
proxy先のアプリへ接続できているのか?
設定ファイルに問題はないか?
という切り分けで役立ちます。
Webアプリが表示されないと、
Next.js壊れた?
とすぐアプリ側を疑いたくなります。
でも、
ブラウザ → Nginx → アプリ
のどこで止まっているのかを見るだけでも、原因をかなり絞れます。
設定を書き換えたら、いきなりreloadする前にnginx -t
Nginxの設定を変更したときに覚えておきたいのが、
nginx -tです。
Nginx公式Docsでは、-t は設定ファイルのsyntaxを確認し、設定から参照されるファイルを開けるかテストするオプションとして説明されています。
参考: https://nginx.org/en/docs/switches.html(外部サイト)
設定に問題がなければ、そのあとreloadできます。
nginx -s reloadreload では新しい設定を読み込み、新しいworker processを開始したあと、古いworkerをgracefulに終了させます。
いきなり設定を反映してNginxごと止めるより、
設定を書く
→ nginx -t
→ 問題なければreload
の順で確認する方が安心です。
reverse proxyを挟むときは、Next.js側の機能にも注意が必要
Nginxを前に置けば全部自動的にうまくいくわけでもありません。
たとえばNext.js App Routerにはstreamingがあります。
Next.jsのSelf-Hostingガイドでは、Nginxなどのproxyを使う場合、streamingを正しく動かすためにbufferingを無効にする必要があるケースが説明されています。
参考: https://nextjs.org/docs/app/guides/self-hosting(外部サイト)
つまり、
Nginxを置いたからOK
ではなく、
後ろで動くアプリがどんなHTTP機能を使うか
も見る必要があります。
キャッシュも同じです。
Next.js側が返すCache-Controlを、CDNやreverse proxyがどう扱うかで挙動が変わることがあります。
Nginxは便利ですが、前段に一枚増える分、設定によってアプリの挙動へ影響することもあります。
結局、Nginxは何をしているのか
最初は、
Next.jsの前に何となく置くもの
くらいに見えていました。
でも役割を分けてみると、かなりシンプルです。
外からHTTP/HTTPSリクエストを受ける。
どのドメイン・URLへのアクセスか判断する。
必要なら静的ファイルを自分で返す。
必要ならNext.jsやAPIへproxyする。
HTTPSを処理する。
アクセスやエラーをログへ残す。
つまり、
Webアプリとインターネットの間に立つ「受付兼案内所」
くらいの理解から始めると、Nginxの設定がかなり読みやすくなります。
そしてNginxはNext.js専用のものでも、Next.jsを動かすために必須のものでもありません。
自前サーバーで公開するときに、
インターネットへ直接アプリを出すのではなく、入口を一段分けたい。
そんなときに強い選択肢です。
自分でサイトを公開してみると、
コードを書いて終わりではなく、そのコードへリクエストがどう届くか
まで見えてきます。
次にNginxの設定を見るときは、directiveを一個ずつ暗記するより、
このリクエストはどこから来て、Nginxがどこへ渡す設定なんだ?
と追ってみる。
それだけでも、listen、server_name、location、proxy_pass がかなり繋がって見えると思います。
