はじめに
F5 BIG-IP などのロードバランサーを導入した際、Web サーバー側のアクセスログを見て「あれ? クライアントの IP ではなく、全部 BIG-IP の IP が記録されている?」と困ったことはありませんか?
本記事では、この問題を解決するための標準的な手法である 「X-Forwarded-For(XFF)」 の設定方法について解説します。
- なぜ Webサーバーにはクライアント IP が届かないのか(SNAT の仕組み)
- X-Forwarded-For の役割とフォーマット
- BIG-IP で XFF を挿入する 具体的な設定手順
なぜ IP が変わってしまうのか?(SNAT の仕組み)
BIG-IP は通常、「フルプロキシ(Full Proxy)」 として動作します。 この際、行きと帰りの通信経路を正しく BIG-IP 経由にするために、SNAT (Source NAT) という機能が使われるのが一般的です。
- SNAT なし
-
サーバーからの戻り通信が、BIG-IP を通らず直接クライアントに帰ってしまう(DSR 構成以外では通信不成立になる)
- SNAT あり
-
BIG-IP が送信元 IP を「自分(BIG-IP)」に書き換えてサーバーに送る。これにより、戻り通信も確実に BIG-IP に戻ってくる。

通信を成立させるために必要な SNAT ですが、副作用として 「Web サーバーに届くパケットの送信元 IP が、すべて BIG-IP になってしまう」 という現象が発生します。 そこで登場するのが XFF です。
X-Forwarded-For (XFF) とは
X-Forwarded-For (XFF) は、HTTP ヘッダフィールドの一つです。 ロードバランサーやプロキシサーバーを経由した際に、「本来のクライアント IP アドレス」 を Web サーバーに伝えるための標準的な手段として使用されます。
通信フローとヘッダの変化
パケットの中身がどう変わるかのざっくりとしたフローは以下になります。
送信元IPは Client です。この時点では XFF ヘッダはありません。
SNAT で送信元IPを BIG-IP に書き換えると同時に、HTTP ヘッダに X-Forwarded-For: Client を挿入 します。
- Web サーバーには送信元
BIG-IPとして届きますが、ヘッダの中を見れば「本当はClientから来たんだな」と分かります。
XFF のフォーマット
XFF フィールドは、以下のような形式で記述されます。
X-Forwarded-For: <クライアントIP>, <プロキシ1>, <プロキシ2>...- 例:
X-Forwarded-For: 203.0.113.10 - 複数のプロキシを経由する場合、カンマ区切りで IP アドレスが追記されていきます。通常、一番左端 にある IP アドレスが、大元のクライアント IP になります。
BIG-IP での設定手順(HTTP プロファイル)
BIG-IP で XFF を挿入するには、Virtual Server に適用されている HTTP プロファイル を編集します。
運用上のトラブルを避けるため、デフォルトの http プロファイルを直接書き換えるのではなく、新しいカスタムプロファイルを作成して適用する 手順を推奨します。
- 管理画面のメニューから 「Local Traffic」>「Profiles」>「Services」>「HTTP」 をクリックします。


- 画面右上の 「Create」 ボタンをクリックします。


- Name に任意のプロファイル名を入力します(例:
http_xff_profile)- Parent Profile が
httpになっていることを確認してください。
- Parent Profile が
設定画面の中ほどにある 「Settings」 エリアを探します。
- Insert X-Forwarded-For の項目にあるチェックボックス(Custom)にチェックを入れます。
- プルダウンメニューから 「Enabled」 を選択します。
- 画面最下部の 「Finished」 をクリックして保存します。


作成したプロファイルを、実際の通信に使っている Virtual Server に紐付けます。
- 「Local Traffic」>「Virtual Servers」 を開き、対象の Virtual Server をクリックします。
- Configuration セクションの HTTP Profile(Client)プルダウンから、先ほど作成したプロファイル(例:
http_xff_profile)を選択します。 - 「Update」 をクリックして適用完了です。


動作確認
設定が完了したら、本当に XFF ヘッダが挿入されているか確認しましょう。
方法①:tcpdump でパケットの中身を見る
BIG-IP の CLI (SSH) で tcpdump コマンドを実行し、サーバーへ送られるパケットの中身を直接覗き見るのが最も確実です。
コマンド例: Web サーバー側のインターフェース(VLAN)を指定してキャプチャします。 -A オプションを付けることで、ヘッダの中身(ASCII 文字)を表示できます。
# internal VLAN に向けた通信、かつポート80番をキャプチャ
tcpdump -ni internal -s0 -A port 80通信を発生させると、大量の文字列が流れます。その中から GET / HTTP/1.1 などのリクエスト行を探し、その下に X-Forwarded-For があるか確認します。
GET / HTTP/1.1
Host: example.com
User-Agent: curl/7.68.0
Accept: */*
X-Forwarded-For: 192.168.100.10 <-- これがあれば成功方法②:Web サーバーのアクセスログで確認する
Web サーバー(Apache, Nginx, IIS)のアクセスログで確認することも可能です。
ただし、Web サーバー側で「XFF の中身をログに記録する設定」が入っていないと、ログには表示されません。 BIG-IP の設定が正しくても、ここでハマるケースが多いので注意してください。
- Apache の場合
-
LogFormatに%{X-Forwarded-For}iを追加する必要があります。 - Nginx の場合
-
ログフォーマットに
$http_x_forwarded_for変数を追加する必要があります。 - IIS の場合
-
「Advanced Logging」モジュールなどを使用し、フィールドを追加する必要があります。



「BIG-IPの設定をしたのにログが変わらない」という場合は、Web サーバー側のログフォーマット設定 が原因の可能性が高いです。 この場合は 方法① (tcpdump) で確認することをおすすめします。
【補足】iRules を使う場合
基本的には先述の「HTTP プロファイル」を使うのが最も高速で推奨される方法ですが、要件によっては iRules(F5 独自のスクリプト言語)を使用するケースがあります。
プロファイルで対応できないケースとは?
例えば以下のような細かい制御が必要な場合です。
- 特定の通信だけに入れたい
-
「
/admin配下のアクセスには入れない」など、パスや条件によって挙動を変えたい場合 - 既存の XFF を信頼しない(セキュリティ)
-
悪意あるクライアントが、偽の
X-Forwarded-Forヘッダを付けて送ってきた場合、プロファイルの標準設定では「追記(Append)」してしまうため、偽の IP がログに残ってしまいます。 「既存のヘッダを削除して、BIG-IP が見た IP だけを記録したい」場合は iRules が必要です。
設定例(サンプルコード)
最もシンプルな、XFF を挿入するだけの iRule は以下のようになります。
when HTTP_REQUEST {
# クライアントのIPアドレスを X-Forwarded-For ヘッダとして挿入
HTTP::header insert X-Forwarded-For [IP::client_addr]
}既存のヘッダを削除して上書きする場合
when HTTP_REQUEST {
# 偽装防止のため、既存の XFF ヘッダがあれば削除
if { [HTTP::header exists X-Forwarded-For] } {
HTTP::header remove X-Forwarded-For
}
# 改めて正しい IP を挿入
HTTP::header insert X-Forwarded-For [IP::client_addr]
}まとめ
本記事では、BIG-IP 環境でクライアント IP を正しく Web サーバーに伝えるための X-Forwarded-For (XFF) 設定について解説しました。
ロードバランサーの導入後、「ログに全部同じ IP が並んでいる」と慌てないように、構築段階でセットすることを推奨します。
以上、最後までお読みいただきありがとうございました。







