手帳

  • 2025-10-16
  • IT系

nginx-proxyとApacheで実IPアドレスを取得する方法(TRUST_DOWNSTREAM_PROXY編)

前回の記事では、リバースプロキシ環境での実IP取得の基礎を学びました。今回は、TRUST_DOWNSTREAM_PROXY という設定の謎と、Cloudflare使用サイトと直接アクセスサイトが混在する環境での完璧な解決策を解説します。

TRUST_DOWNSTREAM_PROXYの謎

nginx-proxyの設定で TRUST_DOWNSTREAM_PROXY という項目を見たことがありますか?この名前、実はかなりミスリーディングなんです。

UPSTREAMとDOWNSTREAMの違い

川の流れで考えるとわかりやすいです:

       上流 (UPSTREAM)              下流 (DOWNSTREAM)
源流 ────→ 上流 ────→ 中流 ────→ 下流 ────→ 河口

ネットワークでは:
訪問者 ────→ Cloudflare ────→ nginx-proxy ────→ Apache
(上流)                        ↑               (下流)
                          ここから見た視点

nginx-proxyから見て、前にいるのが上流、後ろにいるのが下流なんです。

命名の罠

TRUST_DOWNSTREAM_PROXY=true

名前は「DOWNSTREAMを信頼する」ですが、実際には「UPSTREAM(上流)のプロキシを信頼する」という意味なんです!

  • TRUST_DOWNSTREAM_PROXY=true → 上流(CloudflareなどのCDN)が送ってくる X-Forwarded-For ヘッダーを信頼する
  • TRUST_DOWNSTREAM_PROXY=false → 上流のヘッダーを信頼せず、直接接続してきたIPアドレスのみを使う

公式ドキュメントでも “trust forwarded headers from upstream proxies” と説明されているので、名前とは逆なんです。

TRUST_DOWNSTREAM_PROXYの動作

ケース1: Cloudflare使用 + TRUST_DOWNSTREAM_PROXY=true

訪問者(203.0.113.45) → Cloudflare(104.21.x.x) → nginx-proxy
                         ↓ ヘッダーを追加
                    X-Forwarded-For: 203.0.113.45

nginx-proxyの内部動作:
set_real_ip_from 0.0.0.0/0;           # すべてのIPからのヘッダーを信頼
real_ip_header X-Forwarded-For;       # X-Forwarded-For を読み取る
real_ip_recursive on;                  # チェーン全体を処理

結果:
$remote_addr = 203.0.113.45  ✅ 実際の訪問者のIPが取れる!

ケース2: Cloudflare使用 + TRUST_DOWNSTREAM_PROXY=false

訪問者(203.0.113.45) → Cloudflare(104.21.x.x) → nginx-proxy

結果:
$remote_addr = 104.21.x.x  ❌ CloudflareのIPになってしまう

偽装攻撃のリスク

Cloudflareを使っていないのに TRUST_DOWNSTREAM_PROXY=true にすると、攻撃者がIPアドレスを偽装できてしまいます。

# 悪意のある訪問者が偽のヘッダーを送信
curl -H "X-Forwarded-For: 192.168.1.1" https://example.com

nginx-proxyはこれを信じてしまう:
$remote_addr = 192.168.1.1  ⚠️ 偽装されたIP!

何が問題なのか?

  1. アクセス制限の回避:「日本からのみアクセス可」という制限を突破される
  2. ログの改ざん:ログに偽のIPが記録され、攻撃者の追跡ができない
  3. 料金の不正:IPベースの料金課金を回避される
  4. レート制限の無効化:「1IPあたり1分間に10回まで」という制限が無効化される

混在環境の課題

サイトによってCloudflareを使ったり使わなかったりする場合、どうすればいいでしょうか?

TRUST_DOWNSTREAM_PROXYグローバル設定なので、すべてのサイトに影響します:

設定Cloudflare使用サイト直接アクセスサイト
true✅ 実IPが取れる❌ 偽装可能(危険)
false❌ CloudflareのIPになる✅ 実IPが取れる(安全)

どっちに設定しても、どちらかのサイトで問題が起きてしまいます…

完璧な解決策

TRUST_DOWNSTREAM_PROXY=false にしつつ、Cloudflareの特別なヘッダーを使う方法があります!

# custom.conf に追加

# Cloudflareのヘッダーがあるかチェック
map $http_cf_connecting_ip $real_client_ip {
    default $http_cf_connecting_ip;  # CF-Connecting-IP があればそれを使う
    "" $remote_addr;                  # なければ直接接続のIPを使う
}

# このIPをApacheに渡す
proxy_set_header X-Real-IP $real_client_ip;

動作の仕組み

Cloudflare経由の場合:

訪問者(203.0.113.45) → Cloudflare → nginx-proxy → Apache

Cloudflareがヘッダーを追加:
  CF-Connecting-IP: 203.0.113.45

nginx-proxyの処理:
  $http_cf_connecting_ip = "203.0.113.45"  (ヘッダーがある!)
  ↓
  $real_client_ip = "203.0.113.45"
  ↓
  X-Real-IP: 203.0.113.45 をApacheに送信 ✅

直接アクセスの場合:

訪問者(203.0.113.45) → nginx-proxy → Apache

ヘッダーなし:
  CF-Connecting-IP: (なし)

nginx-proxyの処理:
  $http_cf_connecting_ip = ""  (ヘッダーがない)
  ↓
  $real_client_ip = $remote_addr = "203.0.113.45"
  ↓
  X-Real-IP: 203.0.113.45 をApacheに送信 ✅

偽装攻撃の場合:

攻撃者 → nginx-proxy
  X-Forwarded-For: 192.168.1.1  (偽装ヘッダー)
  CF-Connecting-IP: (なし)

nginx-proxyの処理:
  TRUST_DOWNSTREAM_PROXY=false なので X-Forwarded-For は無視!
  $http_cf_connecting_ip = ""
  ↓
  $real_client_ip = $remote_addr = "攻撃者の実IP"
  ↓
  偽装失敗! 🛡️

まとめ

設定Cloudflare使用時直接アクセス時
true✅ 実IPを取得⚠️ 偽装可能(危険)
false❌ CloudflareのIPになる✅ 実IPを取得(安全)
false + map設定✅ 実IPを取得✅ 実IPを取得(推奨

混在環境では false + map設定 が最も安全です。

次回予告

次回の最終回では、Apache側の設定(mod_remoteip)とログフォーマットの詳細を解説します。%a%u%>s などのフォーマット指定子の意味もすべてわかるようになりますよ!

シリーズ記事:

  • 第1部:基礎編(HTTPヘッダーとnginx変数)
  • 第2部:TRUST_DOWNSTREAM_PROXYと混在環境の設定(この記事)
  • 第3部:Apache設定とログフォーマットの詳細(続く)

タグ: nginx, Apache, WordPress, セキュリティ, Cloudflare, TRUST_DOWNSTREAM_PROXY