---
# System prepended metadata

title: Laravel + Nginx 取得真實用戶 IP 設定

---

### **Laravel API 白名單與「真實用戶 IP」技術學習筆記**

#### **前言**

在為 Laravel 應用程式實作 IP 白名單時，我們經常遇到一個核心挑戰：當服務部署在 Cloudflare 或其他反向代理後方時，應用程式直接取得的 IP 位址會是代理伺服器的，而非客戶端的真實來源 IP。這份手冊將系統性地闡述從網路基礎、伺服器配置到 Laravel 框架層，如何正確取得並驗證「真實用戶 IP」，確保白名單機制的安全與精確。

---

#### **1. 核心問題：IP 白名單的基礎——CIDR**

當合作方提供 IP 位址時，通常會以 CIDR（無類別域間路由）格式提供，例如 `192.0.2.0/28`。理解其含義是設定白名單的第一步。

*   **CIDR 格式**：`位址/前綴長度`。可用的主機數量由 `2^(32 − 前綴長度)` 決定（以 IPv4 為例）。

| CIDR | 涵蓋 IP 數量 | 適用情境與安全考量 |
| :--- | :--- | :--- |
| **/32** | **1 個** | **白名單首選**。最小攻擊面，精確指向單一伺服器。 |
| /28 | 16 個 | 適用於對方擁有多個固定出口 IP 的叢集或 NAT 環境。需確認必要性，否則範圍過寬。 |
| /24 | 256 個 | 常見於企業內部網段，但作為 API 白名單通常**過於危險**。 |

**判斷準則**：**永遠優先要求 `/32` 的單一 IP**。僅在對方能明確證明其所有出口 IP 都在一段連續範圍內且皆為固定 IP 時，才考慮接受如 `/28` 的網段。若 IP 不連續，應要求提供多個 `/32` 位址。

---

#### **2. 原理剖析：CDN 如何影響 IP 獲取？**

要解決問題，必須先理解請求的流向。

*   **入站流量 (Inbound)**：`用戶 → CDN/反向代理 → 你的 Nginx 伺服器`
    *   這是訪客或 API 客戶請求你服務的的路徑。請求會先抵達 Cloudflare，再由 Cloudflare 轉發至你的主機。**這是我們需要還原真實 IP 的場景**。
*   **出站流量 (Outbound)**：`你的伺服器 → 外部 API`
    *   這是你的伺服器主動請求外部服務的路徑。流量會直接從你的主機房 ISP 出口，**不受 CDN 影響**。

**結論**：CDN 只影響「入站」請求的來源 IP。若要檢測自己伺服器的出口 IP，可使用 `curl ifconfig.co` 指令（詳見第 6 節）。

---

#### **3. 關鍵標頭：Cloudflare 與多層代理的 IP 識別**

當請求經過 Cloudflare 時，它會將真實的客戶端 IP 資訊附加在 HTTP 標頭 (Header) 中傳遞給後端伺服器。

*   `CF-Connecting-IP`：Cloudflare 官方推薦使用的標頭。它代表 Cloudflare 視角下的「客戶端真實 IP」，通常是單一值，**應優先採信**。
*   `X-Forwarded-For` (XFF)：一個業界標準，記錄了請求經過的每一層代理 IP 鏈，格式為 `client, proxy1, proxy2, ...`。在多層代理環境下較為複雜。
*   其他輔助標頭：`CF-Ray` (請求 ID), `CF-IPCountry` (來源國別), `cdn-loop` (防止代理迴圈)。

---

#### **4. Nginx 實作：「真實 IP 還原」模組（`ngx_http_realip_module`）**

這是整個流程中最核心的步驟：設定 Nginx，使其能讀懂 CDN 傳來的標頭，並將 `$remote_addr` 變數還原為真實 IP。

##### **4.1 核心指令詳解**

```nginx
# 宣告哪些來源的代理是可信的。只有來自這些 IP 的請求，Nginx 才會處理 real_ip_header。
set_real_ip_from <IP或CIDR>;

# 指定哪個 Header 攜帶了真實 IP 位址。
real_ip_header <Header名稱>;

# 在處理 X-Forwarded-For 這類多值標頭時，是否要遞迴解析，跳過可信代理 IP。
real_ip_recursive on|off;
```

##### **4.2 Nginx Cloudflare 推薦設定**

將以下設定加入 `nginx.conf` 的 `http {}` 區塊中，以應用於所有站點。

```nginx
# --- Begin Real IP Configuration ---

# 1. 信任所有 Cloudflare 的 IP 來源（v4 和 v6）
#    注意：此列表應定期從 Cloudflare 官方網站更新：https://www.cloudflare.com/ips/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# ... (此處省略其他 Cloudflare IP 段)
set_real_ip_from 2a06:98c0::/29;
# ... (此處省略其他 Cloudflare IPv6 段)

# 2. 告知 Nginx 從 CF-Connecting-IP 標頭中讀取真實 IP
real_ip_header CF-Connecting-IP;

# 3. 啟用遞迴解析（可選但推薦）
#    雖然 CF-Connecting-IP 是單一值，但開啟此選項無副作用，且能兼容其他代理場景。
real_ip_recursive on;

# --- End Real IP Configuration ---
```

**安全要點**：`set_real_ip_from` 清單**絕對不能**設定為 `0.0.0.0/0` 或 `::/0`，這等同於信任任何來源的 IP 偽造，會造成嚴重安全漏洞。

##### **4.3 流程對照**

| 狀態 | 請求流程 | Nginx `$remote_addr` 結果 |
| :--- | :--- | :--- |
| **無代理** | `用戶 → Nginx` | ✅ **用戶真實 IP** |
| **經 CDN (未設定 RealIP)** | `用戶 → CF → Nginx` | ❌ **Cloudflare 節點 IP** |
| **經 CDN (已正確設定)** | `用戶 → CF → Nginx` | ✅ **用戶真實 IP** |

---

#### **5. Laravel 層：以最簡潔的方式獲取 IP**

當 Nginx 層面已正確還原 `$remote_addr` 後，Laravel 的工作將變得極其簡單。

```php
// 在你的 Middleware 或 Controller 中
$ip = request()->ip(); // 這就是經過還原的、可信的真實 IP (可能是 v4 或 v6)
```

**關於 `TrustProxies` Middleware**：
Laravel 的 `app/Http/Middleware/TrustProxies.php` 用於處理代理。若 Nginx 已完成上述設定，將 `TrustProxies` 的 `$proxies` 設為 `'*'` 是安全的，因為信任邊界已由 Nginx `set_real_ip_from` 嚴格把關。反之，若未設定 Nginx，直接信任所有代理 (`'*'`) 將允許客戶端偽造 `X-Forwarded-For` 標頭，繞過 IP 限制。

---

#### **6. 自我檢測：如何指導客戶提供正確的 IP？**

為了避免溝通誤差，你可以提供明確的指令，讓客戶在他們的伺服器環境中執行，以獲得其準確的出口 IP。

**指令稿：**

> 您好，為了將您的服務加入我們的 API 白名單，請在您**發起 API 請求的伺服器**上執行以下指令，並將回傳的 `ip` 欄位值提供給我們：
>
> *   **若您使用 IPv4 出口**：
>     ```shell
>     curl -4s ifconfig.co/json
>     ```
> *   **若您使用 IPv6 出口**：
>     ```shell
>     curl -6s ifconfig.co/json
>     ```
> *   **若不確定，請兩者皆執行並提供結果。**

這可以確保你拿到的是對方真實的出口 IP，而不是他們辦公室的網路 IP 或其他無關位址。

---

#### **總結：重點步驟回顧**

| 步驟 | 核心任務 | 關鍵指令/方法 | 安全備註 |
| :--- | :--- | :--- | :--- |
| **1. 需求確認** | 向合作方索取 IP | 要求 `/32` 格式 | 避免接受過寬的 CIDR 網段 |
| **2. Nginx 設定** | 還原真實 IP | `set_real_ip_from` + `real_ip_header` | 僅信任 Cloudflare 官方 IP 列表 |
| **3. Laravel 獲取** | 在程式中取得 IP | `request()->ip()` | 確保 Nginx 已正確配置 |
| **4. 客戶指引** | 協助對方自查 IP | `curl -4/-6 ifconfig.co/json` | 避免因資訊錯誤導致的連線問題 |


