Webアプリを「裸」で公開してはいけません。
こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回は、HTMLなどの静的コンテンツを配信する設定をマスターしました。
これで「普通のWebサイト」は作れるようになりましたね。
しかし、現代のWeb開発では、PHPやPython、Node.js、Go、Javaなどを使って動的なアプリケーションを作ることが主流です。
これらのアプリケーションサーバー(APサーバー)は、通常 http://localhost:3000 や 8080 といったポートで動きます。
では、これをインターネットに公開するとき、どうしますか?
「ファイアウォールで3000番を開けて、直接アクセスさせる」…それは絶対にやってはいけません。
先生、ドキッとしました。
Node.jsで作ったアプリ、そのままポート開けて公開してました…。
「動けばいいじゃん」って思ってたんですけど、Nginxを間に挟むとなんかいいことあるんですか?
設定が複雑になりそうで、ちょっと面倒くさいんですけど。
その「面倒」が、あなたのアプリを救うのよ。
Nginxを前段に置く(リバースプロキシ)ことで、セキュリティ向上、SSL化の一元管理、そして負荷分散(ロードバランシング)が可能になるわ。
APサーバーは「アプリの処理」に専念させて、面倒な通信処理は全部Nginxに任せる。
これがプロのアーキテクチャよ!
本記事では、Nginxをリバースプロキシとして構成するための proxy_pass の詳細設定、バックエンドへ正しい情報を伝えるためのヘッダー設定、そして複数のサーバーにアクセスを振り分けるロードバランシングの手法を徹底解説します。
🚀 Nginx基本講座(全8回)カリキュラム
現在地:【第4回】リバースプロキシの構築。APサーバーへの転送とロードバランシング
- 【第1回】Webサーバーの覇者。Nginxのアーキテクチャ解説と最新インストール完全ガイド
- 【第2回】設定ファイルの解剖学。nginx.confの構造とバーチャルホストの基本
- 【第3回】静的コンテンツ配信の極意。root/aliasの使い分けとインデックス設定
- 【第4回】リバースプロキシの構築。APサーバーへの転送とロードバランシング
- 【第5回】HTTPS化とHTTP/3(QUIC)。Let’s EncryptでのSSL証明書自動更新
- 【第6回】鉄壁の守り。アクセス制限、Basic認証、Rate LimitingによるDDoS対策
- 【第7回】爆速化チューニング。Gzip圧縮、ブラウザキャッシュ、バッファサイズ最適化
- 【第8回】ログ解析と運用監視。アクセスログのカスタム設定とDockerでの運用
第1章:リバースプロキシの基本「proxy_pass」
リバースプロキシ(Reverse Proxy)とは、クライアントからのリクエストを「代理」で受け取り、後ろにいるサーバー(バックエンド)へ転送し、その結果を受け取ってクライアントに返す仕組みのことです。
基本設定
バックエンドサーバー(例:Node.jsアプリ)が、同じサーバー内のポート3000番で動いているとします。nginx.conf(または conf.d/app.conf)には以下のように記述します。
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://localhost:3000;
}
}
これだけで、http://app.example.com へのアクセスは、内部的に http://localhost:3000 へ転送されます。
ユーザーからはポート番号が見えず、スマートです。
【重要】末尾スラッシュの罠
proxy_pass を使う際、最も注意すべきなのが「URLの末尾にスラッシュをつけるか、つけないか」です。
これにより、転送されるパス(Path)が変化します。
ケース1:スラッシュなし(そのまま転送)
location /api/ {
proxy_pass http://localhost:3000;
}
- リクエスト:
http://example.com/api/users - 転送先:
http://localhost:3000/api/users - 挙動: locationでマッチしたパス(/api/)も含めて、そのままバックエンドに渡します。
ケース2:スラッシュあり(ルートに置換)
location /api/ {
proxy_pass http://localhost:3000/; # ← ここにスラッシュ!
}
- リクエスト:
http://example.com/api/users - 転送先:
http://localhost:3000/users - 挙動: locationでマッチした部分(/api/)を削除して転送します(第3回の
aliasに似た挙動)。
バックエンドのアプリが /api/ というプレフィックスを想定して作られているかどうかで使い分けます。
迷ったら「スラッシュなし」で運用し、アプリ側でルーティングを合わせるのがトラブルが少ない方法です。
第2章:ヘッダー情報の引き継ぎ「proxy_set_header」
リバースプロキシを通すと、バックエンドサーバーから見た「接続元IPアドレス」は、すべて 127.0.0.1 (NginxのIP) になってしまいます。
これではアクセスログ解析もIP制限もできません。
そこで、Nginxが受け取った真の情報を、HTTPヘッダーに乗せてバックエンドに教えてあげる必要があります。
プロの鉄板設定集
以下の設定は、リバースプロキシを構築する際のおまじない(ベストプラクティス)として覚えておきましょう。
location / {
proxy_pass http://localhost:3000;
# 1. ホスト名をそのまま渡す(必須)
proxy_set_header Host $host;
# 2. クライアントの本当のIPアドレスを渡す
proxy_set_header X-Real-IP $remote_addr;
# 3. プロキシを経由したIPリストを渡す(ロードバランサー経由時に重要)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 4. 元のプロトコル(http/https)を渡す
proxy_set_header X-Forwarded-Proto $scheme;
}
各ヘッダーの意味
- Host: これを設定しないと、バックエンドは自分がどのドメインで呼ばれたか分からず、リダイレクト時に
localhostに飛ばしてしまうなどの不具合が起きます。 - X-Forwarded-For: Webアプリ側で「ユーザーのIPアドレス」を取得したい場合、
REMOTE_ADDRではなく、このヘッダーを参照するようにコードを書く必要があります。
💡 プロのノウハウ:WebSocketへの対応
Socket.ioなどのリアルタイム通信(WebSocket)を使う場合、デフォルト設定では接続が切れてしまいます。
HTTP/1.1へのアップグレードを明示する必要があります。
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
チャットアプリなどを作る際は、この3行をお忘れなく。
第3章:ロードバランシング(負荷分散)の構築
アクセスが増えてくると、1台のAPサーバーでは処理しきれなくなります。
Nginxを使えば、複数のバックエンドサーバーにリクエストを振り分ける「ロードバランサー」を簡単に構築できます。
upstreamブロックの使い方
http コンテキスト内に upstream ブロックを定義し、その中にバックエンドサーバーのリストを書きます。
http {
# バックエンドグループの定義
upstream my_app_servers {
server 192.168.1.101:3000;
server 192.168.1.102:3000;
server 192.168.1.103:3000;
}
server {
listen 80;
server_name app.example.com;
location / {
# 定義したグループ名を指定
proxy_pass http://my_app_servers;
}
}
}
これだけで、リクエストが来るたびに 101 → 102 → 103 → 101… と順番に振り分けられます(ラウンドロビン方式)。
振り分けアルゴリズムの種類
デフォルトのラウンドロビン以外にも、状況に応じた振り分け方が選べます。
- IP Hash (`ip_hash;`):
同じIPアドレスからのアクセスは、常に同じサーバーに飛ばします。
セッション情報(ログイン状態)をサーバー内メモリに保存している場合に必須です。 - Least Connections (`least_conn;`):
現在接続数が最も少ない(暇な)サーバーに優先的に飛ばします。
処理時間がバラバラなリクエストが多い場合に有効です。 - Weight (重み付け):
server 192.168.1.101:3000 weight=3;
性能が良いサーバーに多めにリクエストを送りたい場合に使います。
第4章:ヘルスチェックと切り離し
もしバックエンドの1台が故障してダウンしたらどうなるでしょうか?
Nginxは「応答がない」ことを検知して、自動的にそのサーバーを切り離してくれます(パッシブヘルスチェック)。
パラメータによる調整
upstream my_app_servers {
server 192.168.1.101:3000 max_fails=3 fail_timeout=30s;
server 192.168.1.102:3000 max_fails=3 fail_timeout=30s;
}
- max_fails=3: 3回連続で通信に失敗したら、「ダウンした」とみなします。
- fail_timeout=30s: ダウン判定してから30秒間は、そのサーバーにリクエストを送りません(30秒後に再トライします)。
これにより、ユーザーにエラー画面を見せる確率を劇的に減らすことができます。
メンテナンス時の切り離し
特定のサーバーをメンテナンスしたい場合は、down パラメータを付けます。
server 192.168.1.103:3000 down;
設定をリロード(nginx -s reload)すれば、そのサーバーにはリクエストが飛ばなくなります。
サービスを止めずにメンテナンスができる、インフラエンジニア必須のテクニックです。
第5章:パフォーマンス向上のためのKeepAlive
デフォルトでは、Nginxはバックエンドへのリクエストが終わるたびに接続を切断します。
しかし、高負荷な環境では、接続・切断の繰り返し(TCPハンドシェイク)がオーバーヘッドになります。
upstream ブロック内で keepalive を設定することで、Nginxとバックエンド間の接続を維持(使い回し)できます。
upstream my_app_servers {
server 192.168.1.101:3000;
keepalive 32; # キャッシュする接続数
}
server {
location / {
proxy_pass http://my_app_servers;
# HTTP/1.1を使う(必須)
proxy_http_version 1.1;
# Connectionヘッダーを空にする(必須)
proxy_set_header Connection "";
}
}
これにより、スループット(処理能力)が向上し、遅延が減少します。
第6章:トラブルシューティング(502/504エラー)
リバースプロキシ運用中によく見るエラーと、その原因・対策です。
502 Bad Gateway
- 意味: バックエンドサーバーからの応答が無効、または接続できない。
- 原因: バックエンドのアプリが落ちている、ポート番号が間違っている、Firewallでブロックされている。
- 対策:
curl http://localhost:3000などでバックエンドが生きているか確認する。
504 Gateway Timeout
- 意味: バックエンドサーバーからの応答が時間内に返ってこない。
- 原因: アプリの処理が重すぎてタイムアウトした(例:重い集計処理など)。
- 対策: アプリを高速化するか、Nginxのタイムアウト時間を延ばす。
proxy_read_timeout 600s; # デフォルトは60秒
まとめ:Nginxは「最強の仲介役」
お疲れ様でした!
今回は、Webアプリケーション運用に不可欠なリバースプロキシとロードバランシングについて解説しました。
今回の重要ポイント:
proxy_passは末尾のスラッシュ有無で挙動が変わる。proxy_set_headerでIPアドレスやホスト名をバックエンドに伝える。upstreamを使えば、設定ファイルだけでロードバランサーが作れる。- WebSocketには
Upgradeヘッダーの設定が必要。
これで、Webサイト(静的)もWebアプリ(動的)も、Nginx経由で安全に公開できるようになりました。
しかし、まだURLは http:// のままですよね?
今の時代、通信の暗号化(SSL/TLS)は必須要件です。
次回、第5回は「HTTPS化とHTTP/3(QUIC)。Let’s EncryptでのSSL証明書自動更新」です。
無料で使えるSSL証明書「Let’s Encrypt」の導入方法と、最新の高速プロトコル「HTTP/3」の設定手順を解説します。
あなたのサイトに鍵マーク🔒を付け、さらなる高速化を目指しましょう。お楽しみに!
▼ Nginxの実践環境を手に入れる ▼
アプリを公開するなら
「VPS」で自分専用環境
インフラエンジニアを目指す
「ITエンジニア転職」

コメント