在引入前置代理、CDN 或四層負載均衡之後,閘道器收到的客戶端地址往往變成了代理伺服器的 IP,導致基於使用者真實 IP 的限速、訪問控制和審計日誌全部失效。本文系統梳理 OpenResty Edge 支援的四種真實 IP 還原方案:Proxy Protocol、X-Forwarded-For、X-Real-IP 和自定義頭。涵蓋各方案的適用場景、配置步驟與安全注意事項,並額外說明如何在回源時將真實客戶端 IP 同步傳遞至後端源站,形成完整的入站與出站雙向閉環。您能夠根據自身代理拓撲選擇合適方案,並在 OpenResty Edge 上完成端到端配置。

1. 使用場景與拓撲圖

當請求經過第三方代理轉發時,OpenResty Edge 收到的客戶端地址是代理伺服器的地址,而非真實的終端使用者 IP。

真實客戶端 (104.28.243.40)
        │
        ▼
前置代理伺服器 (52.53.251.226)
        │  攜帶真實 IP 資訊(via XFF / Real-IP / Proxy Protocol)
        ▼
OpenResty Edge 閘道器
        │  還原 client-addr → 用於訪問控制 / 限速 / 日誌
        ▼
後端服務 / 源站

需要還原真實客戶端 IP 的典型場景:

  • 條件判斷:基於使用者真實 IP 的地理位置匹配、黑白名單
  • 請求限速:對單個真實使用者而非代理 IP 進行頻率控制
  • 日誌記錄:審計日誌中記錄真實來源地址

OpenResty Edge 支援四種 IP 傳遞方案,適用於不同的代理拓撲和協議層。

2. IP 傳遞方案概覽與適用場景

方案傳遞層Stream 可用HTTP 可用多級代理
proxy protocolTCP/UDP/TLS 連結頭部資料
X-Forwarded-ForHTTP 頭
X-Real-IPHTTP 頭
自定義頭HTTP 頭取決於實現

Stream 場景約束:TCP/UDP 四層代理中不存在 HTTP 頭,因此所有基於 HTTP 頭的方案均不可用。在本文所討論的方案中,proxy protocol 是 Stream 場景下最主流的選擇;此外,TOA(TCP Option Address)透過將客戶端 IP 寫入 TCP 選項欄位來透傳真實地址,同樣適用於四層代理場景,但其使用依賴核心模組支援,相容性和部署成本與 proxy protocol 存在差異,實際選型需結合具體環境評估。

2.1 proxy protocol V1

核心機制:前置代理在建立 TCP 連線時,於資料流最前端注入一行標準化的 PROXY 頭(以下以 Proxy Protocol v1 格式為例)

PROXY TCP4 <真實客戶端 IP> <代理伺服器 IP> <源埠> <目標埠>\r\n

閘道器在 TCP 層解析該頭部,提取真實 IP 寫入 proxy_protocol_addr,進而更新 client-addr

適用場景:四層 TCP/UDP Stream 代理;HTTP 場景下上游已配置傳送 proxy protocol 頭。

限制條件

  • 前置代理必須主動傳送合規的 proxy protocol V1 頭
  • OpenResty Edge 對應埠須提前啟用 proxy protocol 支援(見 3.1 節)
  • 必須把前置代理伺服器新增到可信的 IP 列表中
  • OpenResty Edge 在同一個埠可以支援多種不同方案的源 IP 傳遞方案。

配置步驟:先在埠級別啟用(3.1 節),再在全域性配置中選擇 Proxy Protocol 來源(3.2 節)。

2.2 Real-IP

核心機制:前置代理將真實客戶端 IP 寫入 X-Real-IP HTTP 頭,由閘道器從中提取並更新 client-addr

適用場景:前置代理負責將終端使用者的真實 IP 統一寫入該頭、且無需在閘道器側還原完整代理鏈路的場景。上游代理可控,寫入邏輯明確即可,不限於單跳拓撲。

限制條件

  • X-Real-IP 無標準規範,不同上游代理的實現行為存在差異:多數實現寫入單個 IP,部分實現(如將其作為 X-Forwarded-For 別名)可能寫入逗號分隔的多值;OpenResty Edge 的處理行為取決於所配置的解析方式,使用前應確認上游寫入格式。
  • 該頭不具備逐跳追加語義,鏈路中間節點的 IP 不會被自動記錄,若需還原完整的多級代理鏈路,應改用 X-Forwarded-For。
  • 僅適用於 HTTP/HTTPS 場景。

2.3 X-Forwarded-For

核心機制:每經過一個代理節點,該節點將入站 IP 追加至 X-Forwarded-For 頭末尾,形成逗號分隔的 IP 列表。

未啟用遞迴搜尋時OpenResty Edge 取 XFF 列表中最右側(最後新增)的 IP 作為客戶端地址。

啟用遞迴搜尋 IP 後:系統從右向左遍歷 XFF 列表,跳過所有在可信來源列表中的地址,取第一個非可信地址作為真實客戶端 IP,可有效抵禦頭部偽造。

適用場景:多級 HTTP 代理鏈路;與主流代理(Nginx、HAProxy、CDN 節點)相容。

限制條件:頭部可被客戶端偽造,必須嚴格配置可信來源 IP(見 3.3 節)。

2.4 自定義頭

核心機制:由運維人員指定任意 HTTP 頭欄位名稱作為真實 IP 來源,OpenResty Edge 從該頭中提取客戶端 IP。

適用場景:內部系統已有私有 IP 傳遞規範(如 CF-Connecting-IPTrue-Client-IP 等);無需修改前置代理的頭部欄位名。

限制條件:前置代理須配合寫入指定頭欄位;僅適用於 HTTP/HTTPS。

3. OpenResty Edge 配置

3.1 閘道器分割槽埠啟用 proxy-protocol 支援

使用 proxy protocol 方案時,必須先在埠級別開啟接收支援,其他方案可跳過此步驟。

  1. 進入 Admin Web 控制檯,導航至 閘道器叢集 > 閘道器分割槽
  2. 選擇目標分割槽,點選右側 編輯 按鈕
  3. 在埠列表中找到目標埠,點選右側 編輯 按鈕
  4. 勾選 啟用 proxy protocol,儲存配置
  5. 在應用配置中選擇想要下發的分割槽

預留埠,請勿將以下埠用於業務配置:80443(預設代理,公網);11212(共享 SSL Session,內網);8090(叢集資源共享,內網);8091(節點狀態查詢,僅本地)。

3.2 全域性配置啟用相關協議

  1. 進入 Global Config 頁面
  2. 客戶端 IP 來源 中選擇實際使用的方案:
選項說明
X-Forwarded-For從 XFF HTTP 頭獲取真實客戶端 IP 和埠
Proxy Protocol從 Proxy Protocol 協議頭獲取(須完成 3.1 節埠配置)
X-Real-IPX-Real-IP HTTP 頭獲取真實客戶端 IP 和埠
Custom Header從自定義 HTTP 頭欄位獲取,需同時填寫頭欄位名稱
  1. (可選)開啟 遞迴搜尋 IP:當頭欄位存在多個 IP 時,從後向前查詢第一個非可信地址作為真實來源 IP,適合多級代理場景。
  2. 儲存後點選 釋出,配置將推送至所有閘道器伺服器,無需過載或重啟

3.3 配置可信來源 IP

Trusted hosts to set real IP 定義了哪些上游地址發來的 Real IP 頭是可信的。只有當 TCP 連線的對端 IP 在此列表中時,OpenResty Edge 才會採信請求頭中的真實 IP 並更新 client-addr;來自不可信地址的請求,其 Real IP 頭將被忽略。

  1. Global Config 頁面找到 Trusted hosts to set real IP
  2. 輸入前置代理伺服器的 IP 地址(示例:52.53.251.226),可新增多條
  3. 儲存併發布

行為對比

請求來源攜帶頭client-addr 結果
52.53.251.226(可信)X-Forwarded-For: 104.28.243.40104.28.243.40
不可信主機X-Forwarded-For: 104.28.243.40不可信主機的實際 IP

注意:真實來源 IP 配置生效後會影響所有依賴客戶端 IP 的功能,包括 Client City、Client Address 顯示、Limit Request Rate 動作等。例外:限制 TLS/SSL 握手速率不受影響,因握手階段發生在 HTTP 層解析之前,此時 client-addr 尚未完成重寫。

3.4 同埠多協議支援說明(對比 Nginx 原生限制)

Nginx 原生行為proxy_protocol 在 Nginx 中是 listen 指令的埠級開關:

# Nginx:同埠只能選擇其一
listen 80 proxy_protocol;   # 該埠只接受帶 proxy protocol 的連線
listen 80;                  # 該埠只接受普通連線

若上游混合傳送(部分攜帶 proxy protocol 頭,部分不攜帶),必須拆分監聽埠分別處理,增加了埠管理和防火牆規則的複雜度。

OpenResty Edge 的處理方式:開啟埠級 proxy protocol 支援後,閘道器能自動識別連線開頭是否為合法的 PROXY 協議頭,並據此選擇解析路徑,同一埠上可同時處理兩類連線:

  • 連線以 PROXY TCP4 ... 開頭 → 解析 proxy protocol 頭,提取真實 IP
  • 連線為普通 HTTP/TCP 流量 → 按常規路徑處理,不要求攜帶協議頭

這一差異化能力在新舊代理混合遷移期間尤為實用,運維團隊無需為不同上游維護不同監聽埠。

4. 關鍵變數說明

4.1 client-addr

client-addrOpenResty Edge最終生效的客戶端地址,貫穿所有與客戶端 IP 相關的處理邏輯。

取值邏輯

  1. 初始值為 TCP 連線的對端 IP(即前置代理地址)
  2. 若該 IP 在可信來源列表中,且請求攜帶有效的 Real IP 頭(或 proxy protocol 頭),則 client-addr 被更新為解析出的真實 IP
  3. 若對端 IP 不在可信列表中,client-addr 保持 TCP 連線來源 IP 不變

影響範圍

  • 頁面規則條件判斷(Client City、Client Address 等變數)
  • Limit Request Rate 限速動作(按真實使用者 IP 限速)
  • 訪問日誌中的客戶端地址欄位
  • EdgeLang 中引用 client-addr 的所有規則

不受影響:TLS/SSL 握手速率限制。握手發生在 HTTP 解析之前,此時 client-addr 尚未完成重寫,使用的仍是 TCP 連線來源 IP。

4.2 proxy_protocol_addr

proxy_protocol_addr 是從 Proxy Protocol 頭中原始提取的客戶端 IP,不經過可信來源規則的過濾。

變數資料來源經過信任規則典型用途
proxy_protocol_addrProxy Protocol 頭原始值審計、除錯
client-addr綜合信任規則後的生效值業務邏輯、限速、日誌

當來源 IP 透過可信驗證時,兩者值相同。當來源 IP 不可信時,proxy_protocol_addr 仍保留協議頭中的解析值,而 client-addr 不會被更新,仍為 TCP 連線來源 IP。在需要同時記錄原始協議頭值和最終生效 IP 的審計場景中,可分別引用兩個變數。

5. 頁面規則

本節配置一條 EdgeLang 頁面規則,使請求響應中直接返回閘道器識別到的 client-addr,作為驗證各 IP 傳遞方案是否生效的基礎。

操作步驟

  1. 進入目標應用(示例:test-edge.com),選擇 Page Rules
  2. 點選 Edit(或新建規則)
  3. 使用 EdgeLang 編寫規則:
# 條件:true(對所有請求生效)
# 動作:在響應體中輸出當前 client-addr 的值
true =>
    say(client-addr),
    done;
  1. 儲存併發布,配置推送至所有閘道器伺服器,無需重啟

釋出後,對該域名的任何請求都將在響應中返回 OpenResty Edge 當前識別到的客戶端地址,可直接用於驗證 IP 傳遞是否正確。

6. 驗證方案

以下驗證均假設目標域名為 test-edge.com,且已按第 5 章完成頁面規則配置。

6.1 curl 攜帶 X-Forwarded-For

前提:Global Config 已選擇 X-Forwarded-For 來源,可信來源 IP 包含發出請求的代理伺服器地址。

單 IP 場景:

curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40"
# 預期輸出:104.28.243.40
# 說明:請求來自可信代理,XFF 頭中的 IP 被採信,client-addr 更新為 104.28.243.40

多 IP 場景(取最後一個):

curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40, 105.56.18.52"
# 預期輸出:105.56.18.52
# 說明:多值時預設取列表最後一個 IP;啟用遞迴搜尋後將跳過可信 IP,取第一個非可信地址

不可信來源驗證:

# 從不在可信列表中的主機發出請求
curl http://test-edge.com/ -H "X-Forwarded-For: 104.28.243.40"
# 預期輸出:該主機自身的出口 IP(如 203.0.113.5)
# 說明:來源不可信,XFF 頭被忽略,client-addr 回退為 TCP 連線來源 IP

6.2 curl 攜帶 X-Real-IP

前提:Global Config 已選擇 X-Real-IP 來源,請求來自可信代理。

curl http://test-edge.com/ -H "X-Real-IP: 104.28.243.40"
# 預期輸出:104.28.243.40
# 說明:閘道器從 X-Real-IP 頭取值,更新 client-addr

6.3 curl 攜帶自定義 HTTP 頭

前提:Global Config 已選擇 Custom Header 來源,並填寫自定義頭名稱(示例:X-My-Real-IP)。請求來自可信代理。

curl http://test-edge.com/ -H "X-My-Real-IP: 104.28.243.40"
# 預期輸出:104.28.243.40
# 說明:閘道器從配置中指定的自定義頭欄位取值,信任規則與其他方案一致

6.4 curl 攜帶 proxy-protocol

前提:目標埠已在閘道器分割槽啟用 proxy protocol(見 3.1 節),Global Config 已選擇 Proxy Protocol 來源。

標準 curl 預設不傳送 proxy protocol 頭,可透過以下方式驗證:

方式一:使用 curl 內建引數(v7.60.0+)

curl http://test-edge.com/ --haproxy-protocol
# 預期輸出:本機出口 IP
# 說明:curl 自動在 TCP 流頭部注入 PROXY 協議頭,閘道器從中提取客戶端 IP

方式二:使用 nc 手動構造,模擬指定真實 IP

printf "PROXY TCP4 104.28.243.40 52.53.251.226 12345 80\r\nGET / HTTP/1.0\r\nHost: test-edge.com\r\n\r\n" \
  | nc test-edge.com 80
# 預期輸出:104.28.243.40
# 說明:手動構造合規的 PROXY 協議頭,閘道器解析後將 proxy_protocol_addr 和 client- addr 均設為 104.28.243.40

7. 延展閱讀

OpenResty Edge 支援在回源請求中透過自定義請求頭(如 X-Real-IP、X-Forwarded-For)將真實客戶端 IP 透傳給後端伺服器,源站無需任何網路層改造即可直接讀取。

推薦參考以下兩篇官方文件深入瞭解:

  1. 如何透過特殊的請求頭傳遞真實的客戶端 IP 地址到後端伺服器 介紹如何在頁面規則中配置回源請求頭,將客戶端 IP 注入到指定 Header 並透傳至後端服務。

  2. 在 OpenResty Edge 中精準還原真實的客戶端 IP 地址 完整講解從"真實來源 IP 信任地址"配置到客戶端地址驗證的全流程,與本文內容互為補充。

關於 OpenResty Edge

OpenResty Edge 是一款專為微服務和分散式流量架構設計的全能型閘道器軟體,由我們自主研發。它集流量管理、私有 CDN 構建、API 閘道器、安全防護等功能於一體,幫助您輕鬆構建、管理和保護現代應用程式。OpenResty Edge 擁有業界領先的效能和可擴充套件性,能夠滿足高併發、高負載場景下的苛刻需求。它支援排程 K8s 等容器應用流量,並可管理海量域名,輕鬆滿足大型網站和複雜應用的需求。

關於作者

章亦春是開源 OpenResty® 專案創始人兼 OpenResty Inc. 公司 CEO 和創始人。

章亦春(Github ID: agentzh),生於中國江蘇,現定居美國灣區。他是中國早期開源技術和文化的倡導者和領軍人物,曾供職於多家國際知名的高科技企業,如 Cloudflare、雅虎、阿里巴巴, 是 “邊緣計算“、”動態追蹤 “和 “機器程式設計 “的先驅,擁有超過 22 年的程式設計及 16 年的開源經驗。作為擁有超過 4000 萬全球域名使用者的開源專案的領導者。他基於其 OpenResty® 開源專案打造的高科技企業 OpenResty Inc. 位於美國矽谷中心。其主打的兩個產品 OpenResty XRay(利用動態追蹤技術的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最適合微服務和分散式流量的全能型閘道器軟體),廣受全球眾多上市及大型企業青睞。在 OpenResty 以外,章亦春為多個開源專案貢獻了累計超過百萬行程式碼,其中包括,Linux 核心、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,並編寫過 60 多個開源軟體庫。

關注我們

如果您喜歡本文,歡迎關注我們 OpenResty Inc. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:

我們的微信公眾號

翻譯

我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!