OpenResty Edge 客戶端真實 IP 全鏈路傳遞指南
在引入前置代理、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 protocol | TCP/UDP/TLS 連結頭部資料 | ✅ | ✅ | ✅ |
| X-Forwarded-For | HTTP 頭 | ❌ | ✅ | ✅ |
| X-Real-IP | HTTP 頭 | ❌ | ✅ | ❌ |
| 自定義頭 | 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-IP、True-Client-IP 等);無需修改前置代理的頭部欄位名。
限制條件:前置代理須配合寫入指定頭欄位;僅適用於 HTTP/HTTPS。
3. OpenResty Edge 配置
3.1 閘道器分割槽埠啟用 proxy-protocol 支援
使用 proxy protocol 方案時,必須先在埠級別開啟接收支援,其他方案可跳過此步驟。
- 進入 Admin Web 控制檯,導航至 閘道器叢集 > 閘道器分割槽
- 選擇目標分割槽,點選右側 編輯 按鈕
- 在埠列表中找到目標埠,點選右側 編輯 按鈕
- 勾選 啟用 proxy protocol,儲存配置
- 在應用配置中選擇想要下發的分割槽
預留埠,請勿將以下埠用於業務配置:80、443(預設代理,公網);11212(共享 SSL Session,內網);8090(叢集資源共享,內網);8091(節點狀態查詢,僅本地)。
3.2 全域性配置啟用相關協議
- 進入 Global Config 頁面
- 在 客戶端 IP 來源 中選擇實際使用的方案:
| 選項 | 說明 |
|---|---|
| X-Forwarded-For | 從 XFF HTTP 頭獲取真實客戶端 IP 和埠 |
| Proxy Protocol | 從 Proxy Protocol 協議頭獲取(須完成 3.1 節埠配置) |
| X-Real-IP | 從 X-Real-IP HTTP 頭獲取真實客戶端 IP 和埠 |
| Custom Header | 從自定義 HTTP 頭欄位獲取,需同時填寫頭欄位名稱 |
- (可選)開啟 遞迴搜尋 IP:當頭欄位存在多個 IP 時,從後向前查詢第一個非可信地址作為真實來源 IP,適合多級代理場景。
- 儲存後點選 釋出,配置將推送至所有閘道器伺服器,無需過載或重啟。
3.3 配置可信來源 IP
Trusted hosts to set real IP 定義了哪些上游地址發來的 Real IP 頭是可信的。只有當 TCP 連線的對端 IP 在此列表中時,OpenResty Edge 才會採信請求頭中的真實 IP 並更新 client-addr;來自不可信地址的請求,其 Real IP 頭將被忽略。
- 在 Global Config 頁面找到 Trusted hosts to set real IP
- 輸入前置代理伺服器的 IP 地址(示例:
52.53.251.226),可新增多條 - 儲存併發布
行為對比:
| 請求來源 | 攜帶頭 | client-addr 結果 |
|---|---|---|
52.53.251.226(可信) | X-Forwarded-For: 104.28.243.40 | 104.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-addr 是 OpenResty Edge 中最終生效的客戶端地址,貫穿所有與客戶端 IP 相關的處理邏輯。
取值邏輯:
- 初始值為 TCP 連線的對端 IP(即前置代理地址)
- 若該 IP 在可信來源列表中,且請求攜帶有效的 Real IP 頭(或 proxy protocol 頭),則
client-addr被更新為解析出的真實 IP - 若對端 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_addr | Proxy Protocol 頭原始值 | 否 | 審計、除錯 |
client-addr | 綜合信任規則後的生效值 | 是 | 業務邏輯、限速、日誌 |
當來源 IP 透過可信驗證時,兩者值相同。當來源 IP 不可信時,proxy_protocol_addr 仍保留協議頭中的解析值,而 client-addr 不會被更新,仍為 TCP 連線來源 IP。在需要同時記錄原始協議頭值和最終生效 IP 的審計場景中,可分別引用兩個變數。
5. 頁面規則
本節配置一條 EdgeLang 頁面規則,使請求響應中直接返回閘道器識別到的 client-addr,作為驗證各 IP 傳遞方案是否生效的基礎。
操作步驟:
- 進入目標應用(示例:
test-edge.com),選擇 Page Rules - 點選 Edit(或新建規則)
- 使用 EdgeLang 編寫規則:
# 條件:true(對所有請求生效)
# 動作:在響應體中輸出當前 client-addr 的值
true =>
say(client-addr),
done;
- 儲存併發布,配置推送至所有閘道器伺服器,無需重啟
釋出後,對該域名的任何請求都將在響應中返回 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 透傳給後端伺服器,源站無需任何網路層改造即可直接讀取。
推薦參考以下兩篇官方文件深入瞭解:
如何透過特殊的請求頭傳遞真實的客戶端 IP 地址到後端伺服器 介紹如何在頁面規則中配置回源請求頭,將客戶端 IP 注入到指定 Header 並透傳至後端服務。
在 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、LuaJIT、GDB、SystemTap、LLVM、Perl 等,並編寫過 60 多個開源軟體庫。
關注我們
如果您喜歡本文,歡迎關注我們 OpenResty Inc. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!

















