頑張らないために頑張る

ゆるく頑張ります

リバースプロキシの基本と実務での使いどころ

Posted at — May 11, 2026

Web アプリを運用していると、ある時点で「外からのアクセスをどうさばくか」「HTTPS をどう終端するか」「複数台構成をどう見せるか」といった課題にぶつかります。そこで登場するのが リバースプロキシ(Reverse Proxy) です。

本記事では、リバースプロキシの基本と実務での使いどころを整理します。

リバースプロキシとは何か

一言で言うと

リバースプロキシは「サーバ側の代理人」です。クライアント(ブラウザや API 呼び出し元)からのリクエストをいったん受け取り、裏側にあるアプリサーバへ中継します。

Client  --->  Reverse Proxy  --->  App Server(s)

クライアントは「本当のアプリサーバ」の存在を意識せず、常にリバースプロキシにアクセスします。

「受付カウンター」のようなもの

大きなオフィスに訪問すると、最初に受付があります。来訪者(クライアント)は受付(リバースプロキシ)に要件を伝え、受付が担当部署(バックエンド)へ案内します。

フォワードプロキシとの違い

alt text

プロキシには大きく 2 種類あります。

種類 代理する対象 典型例
フォワードプロキシ クライアント側の代理 社内ネットワークからの外部 Web アクセス制御
リバースプロキシ サーバ側の代理 Web サービスのフロントに置く Nginx/Apache/ALB

見分け方のコツ

リバースプロキシを置くメリット:実務で効くポイント

HTTPS(TLS)終端を一箇所に集約できる

バックエンドが複数あっても、TLS 証明書の管理をリバースプロキシに集められます。アプリ側は HTTP だけで動かし、フロントで HTTPS を受ける構成が一般的です。

パスやドメインで振り分けできる(ルーティング)

同じドメイン配下でも、パスでアプリを切り替えられます。

ロードバランシングとヘルスチェック(死活監視)ができる

同じアプリを複数台用意し、負荷を分散できます。単に順番に振り分けるだけでなく、プロキシは裏側のサーバが生きているか定期的に確認するヘルスチェック(死活監視)の機能も持ちます。これにより、「ダウンしているサーバにはリクエストを流さない」という賢い制御が可能になり、システムの可用性が向上します。

【注意】プロキシ自体が「単一障害点(SPOF)」になる
バックエンドを10台並べて可用性を高めても、玄関口であるリバースプロキシ(1台)がダウンすればサービス全体が停止します(SPOF: Single Point of Failure)。実務の大規模運用では、リバースプロキシ自身も冗長化するか、AWS ALB などのマネージドサービス(自動でスケール・冗長化される)を採用するのが一般的です。

セキュリティ境界を作れる

圧縮・キャッシュ・ヘッダ付与などの共通処理をまとめられる

アプリごとに実装しがちな「システム全体にまたがる共通処理(ログ・認証・キャッシュなど)」を、フロントに集約できます。

どんな場面で使う?代表的ユースケース

  1. 単一サーバ構成でも

    • HTTPS の終端を簡単にする
    • 静的ファイル配信を高速化する
    • 監視/ログを集約する
  2. 複数サービスを 1 ドメインに集約

    • example.com は共通だが、裏側は複数のアプリ
  3. Blue/Green / Canary リリース

    • 80% を v1、20% を v2 に流す
    • 切り戻しが容易

よくある構成パターン

パスベースのルーティング

                    +--> API Server (localhost:5000)
    Client -> Proxy |
                    +--> Web Server (localhost:3000)

ロードバランシング

    Client -> Proxy -> App1 (10.0.0.11:8080)
                  \-> App2 (10.0.0.12:8080)
                  \-> App3 (10.0.0.13:8080)

実例:Nginx でリバースプロキシ(最小構成)

前提

Nginx 設定例(HTTP → バックエンド)

/etc/nginx/conf.d/app.conf などに以下を置きます。

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:5000;

        # バックエンドに「元の情報」を渡す定番ヘッダ
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket を使う場合に必要になりがち
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

反映して起動します。

sudo nginx -t
sudo systemctl reload nginx

疎通確認:

curl -i http://example.com/

HTTPS 終端(Let’s Encrypt を使う例)

Ubuntu 系なら certbot を使うのが定番です(環境により手順は変わります)。

sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

成功すると Nginx の設定に listen 443 ssl; が追加され、TLS 設定が入ります。
以降、アプリ側は HTTP のままでも、外からは HTTPS で提供できます。

実例:Docker Compose で試す(ローカル検証向け)

「概念はわかったけど手元で動かしたい」場合の最小検証です。
ここではバックエンドを hashicorp/http-echo(受けた内容を返す)で代用します。

docker-compose.yml

services:
  proxy:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app

  app:
    image: hashicorp/http-echo
    command: ["-listen=:5000", "-text=hello from backend"]

nginx.conf

server {
  listen 80;

  location / {
    proxy_pass http://app:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

起動

docker compose up -d
curl -i http://localhost:8080/

hello from backend が返ってくれば成功です。

ハマりどころ

クライアント IP がアプリ側で取れない & 偽装リスク

リバースプロキシ経由だと、バックエンドから見ると「アクセス元は常にプロキシのIP」に見えてしまいます。
そのため X-Forwarded-For などのヘッダを渡し、アプリ側はそれを参照する必要があります。

【致命的なセキュリティの罠】
X-Forwarded-For は悪意のあるユーザーが手元で自由に改ざんして送信できます。アプリ側でこれを信用して IP 制限をかけると、簡単に突破(IPスプーフィング)されてしまいます。アプリ側で設定を有効にする際は、「信頼できるプロキシ(Trusted Proxies)の IP から来た通信の場合のみ、このヘッダを信用する」 という設定が必ずセットで必要です。

パスの付け替えで 404 / 二重パスになる

proxy_pass の末尾スラッシュ有無で挙動が変わることがあります。

どちらが正しいかは「/api/xxx を backend 側で /xxx として扱うか /api/xxx のまま扱うか」で決まります。意図を明確にして設定しましょう。

クラウドのPaaS等をバックエンドにすると 404 / 403 になる

自前のサーバに流す場合は proxy_set_header Host $host; とするのがセオリーですが、外部のクラウドサービス(AWS API Gateway, Cloud Run, Heroku, Vercelなど)をバックエンドにする場合はこの設定が原因でエラーになります。 クラウド側も「Hostヘッダ」を見てどのアプリにルーティングするかを判断しているため、クライアントの元のドメインをそのまま渡すと「知らないドメインだ」と弾かれてしまうのです。

この場合は、バックエンドのドメイン名に Host ヘッダを書き換える必要があります。

# $host ではなく、バックエンドのドメインを指定する
proxy_set_header Host "backend.example.com";

WebSocket / SSE が途切れる・溜め込まれる

リアルタイム通信機能でも、プロキシ特有のハマりどころがあります。

アップロードが失敗する(413 Request Entity Too Large)

Nginx の client_max_body_size がデフォルトだと小さい(1MBなど)場合があります。ファイルアップロードがあるアプリではサイズ上限の緩和が必要です。

client_max_body_size 50m;

リダイレクト URL が http になってしまう

TLS をプロキシで終端していると、バックエンドは「http で受けた」と認識し、リダイレクト生成時(Locationヘッダなど)に http スキームを使ってしまうことがあります。
X-Forwarded-Proto ヘッダでプロキシが受けたスキーム(https)を渡し、アプリ側でそれを信頼して反映させる設定が必要です。

L4 ロードバランサ / API Gateway との違いも軽く押さえる

運用規模が小さければ Nginx などのリバースプロキシで十分なことも多く、要件が増えると API Gateway を検討する、という理解でまずは問題ありません。

まとめ:リバースプロキシは「サービスの玄関口」

リバースプロキシは、単なる中継役ではなく、以下をまとめて引き受ける「玄関口」です。

玄関口である以上、「ここが落ちると全滅する(SPOF)」というインフラ上の弱点でもあります。 まずは 「クライアント → プロキシ → バックエンド」の流れを腹落ちさせ、次に「どの役割をプロキシに持たせたいか」「どれくらいの冗長性が必要か」を要件として整理すると、実務での設計がブレにくくなります。

comments powered by Disqus