差異處
這裏顯示兩個版本的差異處。
| 兩邊的前次修訂版 前次修改 下次修改 | 前次修改 | ||
| tech:http_realip [2025/10/03 19:42] – [Advanced 的設定] jonathan | tech:http_realip [2025/10/03 22:57] (目前版本) – [以下透過一個實驗環境(Cloudflare Tunnel、NPM 與 Docker Swarm 架構)的架構案例進行說明] jonathan | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| ====== 網站取得用戶真實 IP 的方法 ====== | ====== 網站取得用戶真實 IP 的方法 ====== | ||
| - | * 目前網站的網路架構愈來愈複雜, | + | * 目前網站的網路架構愈來愈複雜, |
| + | |||
| + | ==== 通用原則:掌握 HTTP Real IP 標頭 ==== | ||
| + | * 取得真實 IP 的核心在於: | ||
| + | - 識別上游代理伺服器傳來的 真實 IP 標頭(例如:**X-Forwarded-For、CF-Connecting-IP、X-Real-IP**)。 | ||
| + | - 使用 **set_real_ip_from** 信任該標頭的來源 IP 範圍。 | ||
| + | - 使用 **real_ip_header** 指定要讀取的標頭名稱。 | ||
| + | |||
| + | ==== 以下透過一個實驗環境(Cloudflare Tunnel、NPM 與 Docker Swarm 的架構)案例進行說明 | ||
| < | < | ||
| 行 7: | 行 15: | ||
| A[Client - 1.2.3.4] | A[Client - 1.2.3.4] | ||
| B{Cloudflare CDN} | B{Cloudflare CDN} | ||
| - | C[Host A - Cloudflared] | + | C[Host A - 192.168.1.254 |
| D[Host B - 192.168.1.100: | D[Host B - 192.168.1.100: | ||
| - | E[Backend Service - dokuwiki_dokuwiki: | + | E[Docker Swarm Overlay Network - rproxy-net] |
| - | R([Response]) | + | F[Backend Service - dokuwiki_dokuwiki: |
| - | F[Docker Swarm Overlay Network - rproxy-net] | + | |
| | | ||
| %% 2. 結構化 - 邏輯分區 | %% 2. 結構化 - 邏輯分區 | ||
| 行 21: | 行 28: | ||
| subgraph Host B Docker Swarm & NPM | subgraph Host B Docker Swarm & NPM | ||
| %% Host A 到 Host B 的連線 | %% Host A 到 Host B 的連線 | ||
| - | C -- HTTP - LAN 192.168.1.x --> D | + | C -- HTTP - LAN 192.168.1.x |
| %% NPM 經由 Overlay Network 到後端 | %% NPM 經由 Overlay Network 到後端 | ||
| - | D -- HTTP --> E | + | D -- HTTP - rproxy-net 10.0.8.x |
| end | end | ||
| | | ||
| subgraph Backend Service | subgraph Backend Service | ||
| - | E -- dokuwiki-net 接入 --> F | + | E -- rproxy-net 接入 --> F |
| end | end | ||
| - | |||
| - | |||
| - | %% 3. 主要流程連線 | ||
| - | A --> B | ||
| - | B --> C | ||
| - | C --> D | ||
| - | D --> E | ||
| - | E --> R | ||
| | | ||
| %% 4. 補充細節/ | %% 4. 補充細節/ | ||
| - | D -- 連線使用 rproxy-net --> F | ||
| F -- 服務名稱解析 --> E | F -- 服務名稱解析 --> E | ||
| </ | </ | ||
| - | 如果沒有特別設定, | + | 如果沒有特別設定, |
| ===== 1. NPM 必須要將 Port Mode 改成 Host ====== | ===== 1. NPM 必須要將 Port Mode 改成 Host ====== | ||
| 行 80: | 行 78: | ||
| * Forward Hostname / IP : dokuwiki_dokuwiki (假設 Backend Service 的 Stack Name : dokuwiki , Service Name : dokuwiki) | * Forward Hostname / IP : dokuwiki_dokuwiki (假設 Backend Service 的 Stack Name : dokuwiki , Service Name : dokuwiki) | ||
| * Forward Port : 80 | * Forward Port : 80 | ||
| - | ==== Advanced 的設定 ==== | + | |
| - | | + | ==== Advanced 的設定說明 ==== |
| * Host 都在 192.168.1.0/ | * Host 都在 192.168.1.0/ | ||
| # ======================================== | # ======================================== | ||
| 行 115: | 行 113: | ||
| : | : | ||
| </ | </ | ||
| + | < | ||
| + | 當設定 real_ip_recursive on 時,Nginx 會從 X-Forwarded-For 列表的最右邊開始,依序移除屬於 set_real_ip_from 信任範圍內的 IP,直到遇到第一個非信任 IP。由於我們這裡直接使用 real_ip_header CF-Connecting-IP,因此它會被視為真實 IP 並覆蓋 $remote_addr。」 | ||
| + | </ | ||
| + | ===== 3. Backend Service 內的 Nginx Config 設定 ===== | ||
| + | * 因為這 Backend Service 是 dokuwiki 使用的 image 為 lscr.io/ | ||
| + | * 假設 Docker Networks 的 rproxy-net (由 NPM -> Dokuwiki 的 overlay network) 網段是 10.0.8.0/24 | ||
| + | * 在 custom-cont-init.d 內增加 10-nginx-realip.sh < | ||
| + | #!/bin/sh | ||
| + | |||
| + | # 腳本名稱: | ||
| + | # 目的: 修正 Real IP 設定,將其插入到實際的 Nginx 虛擬主機設定檔 (default.conf) 中。 | ||
| + | |||
| + | # Nginx 實際的虛擬主機設定檔路徑 | ||
| + | SITE_CONF="/ | ||
| + | |||
| + | echo ">> | ||
| + | |||
| + | # Real IP 配置內容 | ||
| + | REAL_IP_CONFIG=$(cat <<EOF | ||
| + | # | ||
| + | # Real IP 設定 - 信任 Docker Overlay 網路 (NPM IP) | ||
| + | # | ||
| + | set_real_ip_from 10.0.8.0/ | ||
| + | |||
| + | # 讀取 NPM 傳來的 X-Real-IP 標頭 | ||
| + | real_ip_header X-Real-IP; | ||
| + | |||
| + | EOF | ||
| + | ) | ||
| + | |||
| + | # 檢查配置是否已經存在 | ||
| + | if grep -q " | ||
| + | echo ">> | ||
| + | else | ||
| + | # 這次我們在 ' | ||
| + | SERVER_START=' | ||
| + | |||
| + | # 使用 sed 在 ' | ||
| + | # 使用 \n 和 \t 來處理換行和縮排 | ||
| + | REAL_IP_CONFIG_ESCAPED=$(echo " | ||
| + | |||
| + | if sed -i "/ | ||
| + | echo ">> | ||
| + | else | ||
| + | echo ">> | ||
| + | exit 1 | ||
| + | fi | ||
| + | fi | ||
| + | |||
| + | # 賦予腳本執行權限 | ||
| + | chmod +x " | ||
| + | </ | ||
| + | * 需要將這個 script 檔案設定執行權限 < | ||
| + | * 重新啟動 dokuwiki 這個 stack | ||
| + | * 查看 dokuwiki 啟動的容器 log 應該就會出現類似以下的訊息 < | ||
| + | : | ||
| + | **** Permissions could not be set. This is probably because your volume mounts are remote or read-only. **** | ||
| + | **** The app may not work properly and we will not provide support for it. **** | ||
| + | Existing install found, deleting install.php. | ||
| + | [custom-init] Files found, executing | ||
| + | [custom-init] 10-nginx-realip.sh: | ||
| + | >> [custom-init] Configuring Nginx Real IP in / | ||
| + | >> [custom-init] Real IP configuration already exists in site-conf. Skipping. | ||
| + | [custom-init] 10-nginx-realip.sh: | ||
| + | [ls.io-init] done. | ||
| + | : | ||
| + | </ | ||
| + | * 接下來就可以查看 dokuwiki 的 nginx access log 可以出現用戶 IP Exp. <cli> | ||
| + | : | ||
| + | 15.235.145.214 - - [03/ | ||
| + | 15.235.145.214 - - [03/ | ||
| + | 15.235.145.214 - - [03/ | ||
| + | 217.113.196.92 - - [03/ | ||
| + | 82.97.199.97 - - [03/ | ||
| + | : | ||
| + | </ | ||
| + | |||
| + | {{tag> | ||