フロントプロキシ、CDN、または L4 ロードバランサーを導入すると、ゲートウェイが受け取るクライアントアドレスはプロキシサーバーの IP アドレスになってしまうことがよくあります。これにより、ユーザーのリアル IP に基づいたレート制限、アクセス制御、監査ログがすべて機能しなくなります。本稿では、OpenResty Edge がサポートする 4 つのリアル IP 復元方式(Proxy Protocol、X-Forwarded-For、X-Real-IP、カスタムヘッダー)を体系的に解説します。各方式用の適用シーン、設定手順、セキュリティ上の注意点を網羅し、さらにオリジンへのリクエスト時にリアルクライアント IP をバックエンドのオリジンサーバーに転送し、インバウンドからアウトバウンドまでの完全なループを確立する方法についても説明します。これにより、お客様はご自身のプロキシトポロジーに適した方式を選択し、OpenResty Edge でエンドツーエンドの設定を完了させることが可能になります。

1. ユースケースとトポロジー図

リクエストがサードパーティのプロキシ経由で転送されると、OpenResty Edge が受け取るクライアントアドレスは、真のエンドユーザー IP ではなく、プロキシサーバーのアドレスになります。

リアルクライアント (104.28.243.40)
        │
        ▼
フロントプロキシサーバー (52.53.251.226)
        │  リアル IP 情報を付与 (via XFF / Real-IP / Proxy Protocol)
        ▼
OpenResty Edge ゲートウェイ
        │  client-addr を復元 → アクセス制御 / レート制限 / ログに使用
        ▼
バックエンドサービス / オリジンサーバー

リアルクライアント IP の復元が必要となる典型的なシーン:

  • 条件判定:ユーザーのリアル IP に基づく地理的位置情報でのマッチング、ブラックリスト・ホワイトリスト
  • リクエストレート制限:プロキシ IP ではなく、個々のリアルユーザーに対して頻度を制御
  • ログ記録:監査ログに真の送信元アドレスを記録

OpenResty Edge は、さまざまなプロキシトポロジーやプロトコルレイヤーに対応する、4 つの IP アドレス転送方式をサポートしています。

2. IP アドレス転送方式の概要と適用シーン

方式転送レイヤーStream で利用可能HTTP で利用可能多段プロキシ
proxy protocolTCP/UDP/TLS 接続ヘッダーデータ
X-Forwarded-ForHTTP ヘッダー
X-Real-IPHTTP ヘッダー
カスタムヘッダーHTTP ヘッダー実装に依存

Stream シーンにおける制約:TCP/UDP の L4 プロキシには HTTP ヘッダーが存在しないため、HTTP ヘッダーに基づくすべての方式は利用できません。本稿で解説する方式の中では、proxy protocol が Stream シーンで最も主流な選択肢です。このほか、TOA(TCP Option Address)はクライアント IP を TCP オプションフィールドに書き込むことでリアルアドレスを透過的に転送するもので、同様に L4 プロキシシーンに適用できます。しかし、その利用はカーネルモジュールのサポートに依存し、互換性や導入コストの面で proxy protocol とは差異があるため、実際の選定は具体的な環境に合わせて評価する必要があります。

2.1 proxy protocol V1

コアメカニズム:フロントプロキシが TCP 接続を確立する際に、データストリームの先頭に標準化された一行の PROXY ヘッダーをインジェクトします(以下は Proxy Protocol v1 形式の例です)。

PROXY TCP4 <リアルクライアント IP> <プロキシサーバー IP> <送信元ポート> <宛先ポート>\r\n

ゲートウェイは TCP レイヤーでこのヘッダーを解析し、リアル IP を抽出して proxy_protocol_addr に書き込み、さらに client-addr を更新します。

適用シーン:L4 TCP/UDP Stream プロキシ。HTTP シーンにおいて、アップストリームが proxy protocol ヘッダーを送信するよう設定済みの場合。

制約条件

  • フロントプロキシは、仕様に準拠した proxy protocol V1 ヘッダーを送信する必要があります。
  • OpenResty Edge の対象ポートで、事前に proxy protocol のサポートを有効化しておく必要があります(3.1 節参照)。
  • フロントプロキシサーバーを信頼できる IP リストに追加する必要があります。
  • OpenResty Edge は、同一ポートで複数の異なる送信元 IP 転送方式をサポートできます。

設定手順:まずポートレベルで有効化し(3.1 節)、次にグローバル設定で Proxy Protocol をソースとして選択します(3.2 節)。

2.2 Real-IP

コアメカニズム:フロントプロキシがリアルクライアント IP を X-Real-IP HTTP ヘッダーに書き込み、ゲートウェイがそこから IP を抽出して client-addr を更新します。

適用シーン:フロントプロキシがエンドユーザーのリアル IP をこのヘッダーに書き込み、かつゲートウェイ側でプロキシチェーン全体を復元する必要がないシーン。アップストリームプロキシが制御可能で、書き込みロジックが明確であれば、シングルホップのトポロジーに限定されません。

制約条件

  • X-Real-IP には標準仕様がなく、アップストリームプロキシによって実装や挙動が異なります。多くの実装では単一の IP を書き込みますが、一部の実装(例えば X-Forwarded-For のエイリアスとして使用する場合)ではカンマ区切りの複数値を書き込む可能性があります。OpenResty Edge の処理動作は設定された解析方式に依存するため、使用前にアップストリームの書き込み形式を確認する必要があります。
  • このヘッダーはホップごとに追加していくセマンティクスを持たないため、経路上の中間ノードの IP は自動的に記録されません。多段プロキシのチェーン全体を復元する必要がある場合は、X-Forwarded-For を使用すべきです。
  • HTTP/HTTPS シーンにのみ適用されます。

2.3 X-Forwarded-For

コアメカニズム:プロキシノードを一つ経由するごとに、そのノードが受信した接続元の IP を X-Forwarded-For ヘッダーの末尾に追加し、カンマ区切りの IP リストを形成します。

再帰的検索が無効の場合OpenResty Edge は、XFF リストの最も右側(最後に追加された)の IP をクライアントアドレスとして取得します。

IP の再帰的検索を有効にした場合:システムは XFF リストを右から左へ走査し、信頼できる送信元リストにあるアドレスをすべてスキップし、最初に見つかった信頼できないアドレスをリアルクライアント IP とします。これにより、ヘッダーの偽装を効果的に防御できます。

適用シーン:多段 HTTP プロキシチェーン。主要なプロキシ(Nginx、HAProxy、CDN ノード)と互換性があります。

制約条件:ヘッダーはクライアントによって偽装される可能性があるため、信頼できる送信元 IP を厳格に設定する必要があります(3.3 節参照)。

2.4 カスタムヘッダー

コアメカニズム:運用担当者が任意の HTTP ヘッダーフィールド名をリアル IP のソースとして指定し、OpenResty Edge がそのヘッダーからクライアント IP を抽出します。

適用シーン:内部システムで既にプライベートな IP 転送仕様(例:CF-Connecting-IPTrue-Client-IP など)が存在する場合。フロントプロキシのヘッダーフィールド名を変更する必要がない場合。

制約条件:フロントプロキシ側で、指定されたヘッダーフィールドへの書き込み設定が必要です。HTTP/HTTPS シーンにのみ適用されます。

3. OpenResty Edge の設定

3.1 ゲートウェイパーティションのポートで proxy-protocol サポートを有効化

proxy protocol 方式を使用する場合、他の方式では不要ですが、まずポートレベルで受信サポートを有効にする必要があります。

  1. Admin Web コンソールに入り、ゲートウェイクラスター > ゲートウェイパーティション に移動します。
  2. 対象のパーティションを選択し、右側の 編集 ボタンをクリックします。
  3. ポートリストから対象のポートを見つけ、右側の 編集 ボタンをクリックします。
  4. proxy protocol を有効にする にチェックを入れ、設定を保存します。
  5. アプリケーション設定で、この設定を適用したいパーティションを選択します。

予約済みポート:以下のポートを業務設定に使用しないでください:80443(デフォルトプロキシ、パブリックネットワーク);11212(SSL セッション共有、プライベートネットワーク);8090(クラスターリソース共有、プライベートネットワーク);8091(ノード状態クエリ、ローカルのみ)。

3.2 グローバル設定で関連プロトコルを有効化

  1. Global Config ページに移動します。
  2. クライアント IP ソース で、実際に使用する方式を選択します:
オプション説明
X-Forwarded-ForXFF HTTP ヘッダーからリアルクライアント IP とポートを取得します
Proxy ProtocolProxy Protocol ヘッダーから取得します(3.1 節のポート設定を完了する必要があります)
X-Real-IPX-Real-IP HTTP ヘッダーからリアルクライアント IP とポートを取得します
Custom Headerカスタム HTTP ヘッダーフィールドから取得します。同時にヘッダーフィールド名を入力する必要があります
  1. (オプション)IP の再帰的検索を有効にする:ヘッダーフィールドに複数の IP が存在する場合、後ろから前(右から左)に検索し、最初に見つかった信頼できないアドレスをリアル送信元 IP とします。これは多段プロキシのシーンに適しています。
  2. 保存後、公開 をクリックすると、設定はすべてのゲートウェイサーバーにプッシュされます。リロードや再起動は不要です

3.3 信頼できる送信元IPの設定

Trusted hosts to set real IP は、どのアップストリームアドレスから送信された Real IP ヘッダーが信頼できるかを定義します。TCP 接続のリモート IP がこのリストに存在する場合にのみ、OpenResty Edge はリクエストヘッダー内のリアル IP を信用して client-addr を更新します。信頼できないアドレスからのリクエストの場合、その Real IP ヘッダーは無視されます。

  1. Global Config ページで Trusted hosts to set real IP を見つけます。
  2. フロントプロキシサーバーの IP アドレスを入力します(例:52.53.251.226)。複数追加可能です。
  3. 保存して公開します。

挙動の比較:

リクエスト元付与されたヘッダーclient-addr の結果
52.53.251.226(信頼できる)X-Forwarded-For: 104.28.243.40104.28.243.40
信頼できないホストX-Forwarded-For: 104.28.243.40信頼できないホスト自身の IP

注意:リアル送信元 IP の設定が有効になると、Client City、Client Address の表示、Limit Request Rate アクションなど、クライアント IP に依存するすべての機能に影響します。例外:TLS/SSL ハンドシェイクのレート制限は影響を受けません。ハンドシェイク段階は HTTP レイヤーの解析前に行われ、その時点では client-addr がまだ書き換えられていないためです。

3.4 同一ポートでの複数プロトコルサポートについて(Nginxネイティブの制限との比較)

Nginx ネイティブの挙動:Nginx において、proxy_protocollisten ディレクティブのポート単位のスイッチです。

# Nginx:同一ポートではどちらか一方しか選択できない
listen 80 proxy_protocol;   # このポートはproxy protocol付きの接続のみ受け付ける
listen 80;                  # このポートは通常の接続のみ受け付ける

アップストリームが混在して(一部は proxy protocol ヘッダーを付与し、一部は付与せずに)送信する場合、リスニングポートを分けて個別に対応する必要があり、ポート管理とファイアウォールルールの複雑性が増します。

OpenResty Edge の処理方式:ポートレベルで proxy protocol サポートを有効にすると、ゲートウェイは接続の先頭が正当な PROXY プロトコルヘッダーであるかを自動的に識別し、それに基づいて解析パスを選択します。これにより、同一ポート上で 2 種類の接続を同時に処理できます。

  • 接続が PROXY TCP4 ... で始まる場合 → proxy protocol ヘッダーを解析し、リアル IP を抽出
  • 接続が通常の HTTP/TCP トラフィックの場合 → 通常のパスで処理し、プロトコルヘッダーは要求しない

この差別化された機能は、新旧プロキシが混在する移行期間において特に実用的であり、運用チームは異なるアップストリームのために異なるリスニングポートを維持管理する必要がありません。

4. 主要な変数の説明

4.1 client-addr

client-addr は、OpenResty Edge において最終的に有効となるクライアントアドレスであり、クライアント IP に関連するすべての処理ロジックで一貫して使用されます。

値の取得ロジック:

  1. 初期値は TCP 接続のリモート IP(つまりフロントプロキシのアドレス)です。
  2. その IP が信頼できる送信元リストにあり、かつリクエストが有効な Real IP ヘッダー(または proxy protocol ヘッダー)を付与している場合、client-addr は解析されたリアル IP に更新されます。
  3. リモート IP が信頼できるリストにない場合、client-addr は TCP 接続の送信元 IP のまま変更されません。

影響範囲:

  • ページルールの条件判定(Client City、Client Address などの変数)
  • Limit Request Rate レート制限アクション(リアルユーザー IP に基づくレート制限)
  • アクセスログのクライアントアドレスフィールド
  • EdgeLang で client-addr を参照するすべてのルール

影響を受けないもの:TLS/SSL ハンドシェイクのレート制限。ハンドシェイクは HTTP 解析前に行われ、この時点では client-addr はまだ書き換えられておらず、使用されるのは TCP 接続の送信元 IP です。

4.2 proxy_protocol_addr

proxy_protocol_addr は、Proxy Protocol ヘッダーから元データとして抽出されたクライアント IP であり、信頼できる送信元ルールのフィルタリングを受けません。

変数データソース信頼ルール適用典型的な用途
proxy_protocol_addrProxy Protocol ヘッダーの生の値いいえ監査、デバッグ
client-addr信頼ルール適用後の有効な値はいビジネスロジック、レート制限、ログ

送信元 IP が信頼性検証をパスした場合、両者の値は同じになります。送信元 IP が信頼できない場合、proxy_protocol_addr はプロトコルヘッダーから解析した値を保持しますが、client-addr は更新されず、TCP 接続の送信元 IP のままとなります。プロトコルヘッダーの元の値と最終的に有効な IP を同時に記録する必要がある監査シーンでは、2 つの変数をそれぞれ参照できます。

5. ページルール

本節では、EdgeLang のページルールを一つ設定します。これにより、リクエストのレスポンスで、ゲートウェイが認識した client-addr を直接返すようになり、各 IP 転送方式が有効に機能しているかを検証するための基礎となります。

操作手順

  1. 対象のアプリケーション(例:test-edge.com)に移動し、Page Rules を選択します。
  2. Edit をクリックします(または新規ルールを作成します)。
  3. EdgeLang を使用してルールを記述します:
# 条件:true(すべてのリクエストに適用)
# アクション:レスポンスボディに現在の client-addr の値を出力
true =>
    say(client-addr),
    done;
  1. 保存して公開すると、設定は再起動不要ですべてのゲートウェイサーバーにプッシュされます。

公開後、このドメインへのすべてのリクエストは、レスポンス内で OpenResty Edge が現在認識しているクライアントアドレスを返すようになります。これにより、IP 転送が正しく行われているかを直接検証できます。

6. 検証方法

以下の検証はすべて、対象ドメインが test-edge.com であり、かつ第 5 章に従ってページルールが設定済みであることを前提とします。

6.1 curl で X-Forwarded-For を付与する場合

前提条件:Global Config で X-Forwarded-For がソースとして選択されており、信頼できる送信元 IP に、リクエストを送信するプロキシサーバーのアドレスが含まれていること。

単一 IP のシーン:

curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40"
# 期待される出力:104.28.243.40
# 説明:リクエストが信頼できるプロキシから送信され、XFF ヘッダー内の IP が採用され、client-addr が 104.28.243.40 に更新されます。

複数 IP のシーン(最後の IP を取得):

curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40, 105.56.18.52"
# 期待される出力:105.56.18.52
# 説明:複数値の場合、デフォルトではリストの最後の IP が取得されます。再帰的検索を有効にすると、信頼できる IP をスキップし、最初の信頼できないアドレスが取得されます。

信頼できない送信元からの検証:

# 信頼リストにないホストからリクエストを送信
curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40"
# 期待される出力:そのホスト自身の出口 IP(例:203.0.113.5)
# 説明:送信元が信頼できないため、XFF ヘッダーは無視され、client-addr は TCP 接続の送信元 IP にフォールバックします。

6.2 curl で X-Real-IP を付与する場合

前提条件:Global Config で X-Real-IP がソースとして選択されており、リクエストが信頼できるプロキシから送信されること。

curl http://test-edge.com/ -H "X-Real-IP: 104.28.243.40"
# 期待される出力:104.28.243.40
# 説明:ゲートウェイが X-Real-IP ヘッダーから値を取得し、client-addr を更新します。

6.3 curl でカスタム HTTP ヘッダーを付与する場合

前提条件:Global Config で Custom Header がソースとして選択されており、カスタムヘッダー名(例:X-My-Real-IP)が入力されていること。リクエストが信頼できるプロキシから送信されること。

curl http://test-edge.com/ -H "X-My-Real-IP: 104.28.243.40"
# 期待される出力:104.28.243.40
# 説明:ゲートウェイが設定で指定されたカスタムヘッダーフィールドから値を取得します。信頼ルールは他の方式と同様です。

6.4 curl で proxy-protocol を付与する場合

前提条件:対象ポートがゲートウェイパーティションで proxy protocol を有効にしており(3.1 節参照)、Global Config で Proxy Protocol がソースとして選択されていること。

標準の curl はデフォルトでは proxy protocol ヘッダーを送信しないため、以下の方法で検証できます。

方法 1:curl の組み込みパラメータを使用(v7.60.0 以降)

curl http://test-edge.com/ --haproxy-protocol
# 期待される出力:自マシンの出口IP
# 説明:curl が TCP ストリームの先頭に PROXY プロトコルヘッダーを自動でインジェクトし、ゲートウェイがそこからクライアント IP を抽出します。

方法 2:nc を使用して手動で構築し、指定のリアル IP をシミュレート

printf "PROXY TCP4 104.28.243.40 52.53.251.226 12345 80\r\nGET / HTTP/1.0\r\nHost: test-edge.com\r\n\r\n" \
  | nc test-edge.com 80
# 期待される出力:104.28.243.40
# 説明:仕様に準拠した PROXY プロトコルヘッダーを手動で構築すると、ゲートウェイが解析後、proxy_protocol_addr と client-addr の両方を 104.28.243.40 に設定します。

7. 関連資料

OpenResty Edge は、オリジンへのリクエストにおいて、カスタムリクエストヘッダー(X-Real-IP、X-Forwarded-For など)を介して、リアルクライアント IP をバックエンドサーバーへ透過的に転送することをサポートしています。これにより、オリジンサーバーはネットワークレイヤーの改修を一切行うことなく、直接 IP を読み取ることができます。

より深く理解するために、以下の 2 つの公式ドキュメントを参照することをお勧めします。

  1. 特殊リクエストヘッダーで真のクライアント IP をバックエンドサーバーに渡す方法 ページルールでオリジンリクエストヘッダーを設定し、クライアント IP を指定のヘッダーにインジェクトしてバックエンドサービスへ透過的に転送する方法を紹介します。

  2. OpenResty Edge で真のクライアント IP アドレスを正確に復元する 「信頼できるリアル IP 送信元アドレス」の設定からクライアントアドレスの検証までの全プロセスを完全に解説しており、本稿の内容を補完するものです。

OpenResty Edge について

OpenResty Edge は、マイクロサービスと分散トラフィックアーキテクチャ向けに設計された多機能ゲートウェイソフトウェアで、当社が独自に開発しました。トラフィック管理、プライベート CDN 構築、API ゲートウェイ、セキュリティ保護などの機能を統合し、現代のアプリケーションの構築、管理、保護を容易にします。OpenResty Edge は業界をリードする性能と拡張性を持ち、高並発・高負荷シナリオの厳しい要求を満たすことができます。K8s などのコンテナアプリケーショントラフィックのスケジューリングをサポートし、大量のドメイン名を管理できるため、大規模ウェブサイトや複雑なアプリケーションのニーズを容易に満たすことができます。

著者について

章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。

章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しております。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」、「動的トレーシング」、「機械プログラミング」 の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っております。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立いたしました。同社の主力製品である OpenResty XRay動的トレーシング技術を利用した非侵襲的な障害分析および排除ツール)と OpenResty Edge(マイクロサービスおよび分散トラフィックに最適化された多機能ゲートウェイソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ております。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJITGDBSystemTapLLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しております。

翻訳

英文版 の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!