
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!
何が問題なのか?
- アクセス制限の回避:「日本からのみアクセス可」という制限を突破される
- ログの改ざん:ログに偽のIPが記録され、攻撃者の追跡ができない
- 料金の不正:IPベースの料金課金を回避される
- レート制限の無効化:「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