リバースプロキシ入門
1. リバースプロキシとは何者か
あなたがブラウザで https://example.com/api/users
にアクセスするとき、実際にレスポンスを返しているのはアプリケーションサーバではなく リバースプロキシ かもしれません。リバースプロキシ(以降 RP)は、クライアントとサーバの間に立ち、全リクエストを受け取ってからバックエンドに振り分ける「門番」です。
A[ブラウザ] -->|HTTP(S) リクエスト| RP(リバースプロキシ)
RP -->|内部 HTTP| B[App サーバ 1]
RP --> C[App サーバ 2]
RP --> D[静的ファイル S3 など]
- Forward Proxy は社内ネットワーク→インターネットの出口、
- Reverse Proxy は外部→社内サーバ群の入口。
役割は大きく 4 つ:
- 負荷分散:複数サーバへ Round‑Robin 等で振り分け
- TLS 終端:証明書を RP に集約し、内部は HTTP
- キャッシュ・圧縮:静的レスポンスをキャッシュ、Gzip 送出
- CORS & 認証:同一オリジン問題を迂回し、JWT 等を検証
これにより可用性とセキュリティを両立させつつ、運用コストを抑えられます。(cloudflare.com, strongdm.com)
2. Angular 開発サーバでの即席 RP ─ proxy.conf.json
Angular CLI の ng serve
(内部は webpack‑dev‑server)が提供する “開発用 RP” を使えば、API が別ポート で動いていても CORS に悩まされません。
# プロジェクト直下
$ tree -L 1
├── src
│ └── proxy.conf.json
└── angular.json
2.1 最小構成
{
"/api": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true,
"logLevel": "info"
}
}
-
/api/**
を localhost:3000 へ転送 -
secure:false
は自己署名証明書を許可 -
changeOrigin:true
で Host ヘッダを書き換える(angular.io)
angular.json
の serve オプションへ登録すれば ng serve
だけで自動読み込み:
"serve": {
"options": {
"proxyConfig": "src/proxy.conf.json"
}
}
2.2 ベースパス置換
/backend/users
→ /users
に書き換えて送りたい場合は pathRewrite
:
{
"/backend/*": {
"target": "http://api.local:8080",
"pathRewrite": { "^/backend": "" }
}
}
2.3 環境別にファイル分割
proxy.dev.json # localhost
proxy.stg.json # stg.internal.example
proxy.prd.json # api.example.com
CI/CD で --proxy-config
を差し替えるだけで複数環境を回せます。
3. 開発・テストを“爆速”にする Tips
シーン | オプション | 例 |
---|---|---|
WebSocket がある | "ws": true |
ソケット通信をローカルから中継 |
API プレフィックスが日替わり | "pathRewrite" |
/v42/ → /v43/ へ一括変換 |
詳細ログ | "logLevel": "debug" |
転送ヘッダを確認 |
ファイルアップロード | "buffer": true |
ストリーミングではなくバッファリング |
ワンポイント:
Access-Control-Allow-*
ヘッダを書き換える副作用で、バックエンドの CORS 設定が隠れることがあります。セキュリティレビュー時は RP が付与するヘッダを 必ず 確認しましょう。(github.com, reddit.com)
4. 本番配備での拡張
開発中は Angular の内蔵 RP で十分ですが、本番では nginx / Apache / CloudFront などを使います。たとえば nginx なら:
server {
listen 443 ssl;
server_name example.com;
location / {
root /var/www/app;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://api_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
ここでもパスリライト・キャッシュ・Rate Limiting が自在。開発で確立した URL ルールをそのまま持ち込み、ゼロCORS かつ セッション一元管理 を実現できます。
5. まとめ
- RP は「入口を一本化」して 負荷分散 / TLS / セキュリティ / CORS 回避 を同時に達成
- Angular CLI の
proxy.conf.json
でローカルに簡易 RP を立てれば サーバ変更なし でフロントを実装可能 -
pathRewrite
や 環境分割で ブランチごとに API 先を替える など、テストフローが劇的に加速 - 本番では nginx など正規 RP に移行し、開発で使ったルーティングを踏襲するとスムーズ
6. 代表的ユースケースと“RP が無いと困る”シチュエーション
6.1 BFF(Backend‑for‑Frontend)パターン
モバイルアプリ・Web SPA・Wearable など 異なるクライアント からの要求を単一の GraphQL や REST BFF が受け取り、
RP が実際のマイクロサービスへ “細かい” HTTP 呼び出しをまとめてくれる。
結果としてクライアント側は API バージョン変更を意識せずに済み、リリースの独立性が向上。
6.2 ブルーグリーン/カナリアリリース
/api
を v1 クラスタと v2 クラスタに 90:10 で振り分けて段階的にトラフィックを移行。
RP のルーティングテーブルを書き換えるだけなので ゼロダウンタイム でデプロイが可能。
6.3 IoT ゲートウェイ
ファクトリー内の PLC やセンサーデバイスをインターネットに直接公開するのは危険。
RP を DMZ に置いて WebSocket/TCP を仲介し、双方向通信をエッジ側で終端。
エンジニアは証明書や ACL を一箇所に集約できる。
RP が無い場合、各サービスが 個別に TLS 証明書・認可ロジック・レート制御 を実装しなければならず、
“同じロジックのコピペ地獄” に陥る。障害調査時もログが散在し、MTTR が伸びがち。
7. ロードバランシング・ヘルスチェックの実際
多くの RP 実装(nginx, HAProxy, Envoy)は以下を内蔵:
- Round‑Robin: シンプルに順番で振る
- Least Connections: 接続数が少ないノードへ集中させ過負荷を防ぐ
- IP Hash: 同一クライアントを同じサーバに固定(ステートフルなセッション向け)
-
Active Health Check:
/healthz
を定期的にポーリングし、5xx 回数やレスポンスタイムで重み付け - Passive Health Check: 実リクエスト中のエラー率を監視
Angular の開発用 RP にはさすがにここまで付いていないが、本番での拡張ポイント として覚えておくと運用トラブルの“手札”が増える。
8. セキュリティの注意点
-
ヘッダの上書き:
X-Forwarded-For
,X-Real-IP
を必ず付与しないと、
バックエンド側でクライアント IP が正しく取れない。 - HTTP→HTTPS リダイレクト:RP で 80→443 を強制し、HSTS を追加
- オープンリレー禁止:誤設定で 任意ホストへのプロキシ になら