使用 $_SERVER['HTTP_HOST'] 或 $_SERVER['SERVER_ADDR'] 獲取伺服器 IP 時,若架構包含反向代理(Nginx、CDN、負載均衡器),取得的往往是內網 IP 或代理 IP,而非真實對外 IP。
| 變數 | 說明 | 代理環境下表現 |
|---|---|---|
| HTTP_HOST | 客戶端請求的 Host 標頭 | 可能是代理轉發的內網域名/IP |
| SERVER_ADDR | 伺服器網卡綁定 IP | 通常是內網 IP(如 10.x.x.x, 192.168.x.x) |
| HTTP_X_FORWARDED_FOR | 客戶端真實 IP 鏈(代理附加) | 格式:client, proxy1, proxy2 |
| HTTP_X_FORWARDED_HOST | 原始請求的 Host | 保留原始域名,繞過代理修改 |
| HTTP_X_REAL_IP | Nginx 常用單一真實 IP | 需代理配置 proxy_set_header X-Real-IP $remote_addr; |
function getServerRealIP() {
// 1. 優先檢查代理轉發的原始 Host(適用於虛擬主機場景)
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
return $_SERVER['HTTP_X_FORWARDED_HOST'];
}
// 2. 其次使用標準 Host(無代理或代理透傳時)
if (!empty($_SERVER['HTTP_HOST'])) {
return $_SERVER['HTTP_HOST'];
}
// 3. 最後回退 SERVER_ADDR(僅能獲取伺服器綁定 IP)
return $_SERVER['SERVER_ADDR'] ?? 'unknown';
}
// 獲取客戶端真實 IP(非伺服器 IP)
function getClientRealIP() {
$headers = [
'HTTP_X_FORWARDED_FOR', // 標準代理鏈
'HTTP_X_REAL_IP', // Nginx 常用
'HTTP_CLIENT_IP', // 部分代理使用
'HTTP_CF_CONNECTING_IP', // Cloudflare
'REMOTE_ADDR' // 直連或最後回退
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
// X-Forwarded-For 可能包含多個 IP,取第一個非私有 IP
$ips = array_map('trim', explode(',', $_SERVER[$header]));
foreach ($ips as $ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
// 都為私有 IP 時返回第一個
return $ips[0];
}
}
return 'unknown';
}
location / {
proxy_pass https://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
// Laravel: config/app.php 'trusted_proxies' => ['10.0.0.0/8', '192.168.0.0/16'], // 內網代理範圍 // 控制器中直接使用 $request->ip(); // 自動解析真實客戶端 IP $request->getHost(); // 自動解析真實 Host // Symfony: Request::setTrustedProxies() Request::setTrustedProxies(['10.0.0.0/8'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST);