🌐 Nginx Reverse Proxy Advanced:Multisite、Rewrite、Caching、Load Balancing 全攻略
在現代 Web 架構裡,Nginx Reverse Proxy(反向 Proxy) 幾乎是標配:
一個對外的入口層,背後可以是多台 Web Server、Application Server、API、微服務、甚至是不同網段中的內部系統。
很多人只用 Nginx 轉發幾個後端服務就停手,但在實務上,我們常常會遇到:
- 同一個網域下要服務多個應用:
/app1、/app2、/grafana… - 同一個 IP 要承載多個網域(Multisite):
app.example.com、api.example.com… - 想用 Rewrite 統一網址結構,避免舊連結 404。
- 希望前端帶一層 快取與負載均衡,減輕後端壓力。
本文從概念、架構,到實際設定範例與排錯心法,一次整理 Nginx Reverse Proxy 的進階玩法, 幫你把 Nginx 打造成穩定、可觀測、可擴充的前端入口層。
📑 目錄
- 一、Nginx Reverse Proxy 的角色與核心概念
- 二、最小可用範例:單一服務 Reverse Proxy
- 三、多站點架構:Host-Based 與 Path-Based Routing
- 四、Rewrite 與 URL 設計:return / rewrite / try_files
- 五、Nginx Proxy Cache:為後端減壓的快取層
- 六、Load Balancing:多台後端的流量分散策略
- 七、X-Forwarded-* 與 Header 處理:讓後端知道真實世界
- 八、Timeout / Buffer / 限制值:避免莫名斷線與爆記憶體
- 九、排錯與實戰心法:502/504、迴圈 Redirect、Header 問題
- 十、常見問題 FAQ
- 🧭 行動清單:如何把這些設定落地到你的環境?
- 🔗 延伸閱讀
一、Nginx Reverse Proxy 的角色與核心概念
Nginx 在入口層主要扮演幾個角色:
- Reverse Proxy:接收 Client 請求,再幫它轉發到內部服務。
- 集中 TLS 終結:對外只在 Nginx 做 HTTPS,內部與後端採 HTTP。
- URL 與 Host Routing:依 Hostname、URL 路徑分流到不同服務。
- 快取與壓縮:靜態檔案與可快取 API 由前端先擋住大量流量。
- 負載均衡:一組 upstream 背後可以掛多台後端。
核心觀念是:對外只看到 Nginx;對內由它掌控一切請求應該去哪裡、以什麼樣的速度與規則送達。
二、最小可用範例:單一服務 Reverse Proxy
先從最基本的例子開始:Nginx 接住 https://app.example.com,背後是一台在內部網段的 Web 服務。
# /etc/nginx/conf.d/app.conf
server {
listen 80;
server_name app.example.com;
# 若已在外部做 TLS 終結,可先用 HTTP;若要 Nginx 終結 TLS 則改為 listen 443 ssl ...
location / {
proxy_pass http://10.0.10.20:8080;
# 基本 Header 傳遞
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-Proto $scheme;
}
}
檢查設定並重新載入:
sudo nginx -t
sudo systemctl reload nginx
這就是最小可用的 Reverse Proxy 配置,但實務上我們還會想要:
- 多個網域 / 子網域(Host-Based Multisite)。
- 同網域下依照路徑分流到不同服務(Path-Based Routing)。
- 在入口層做快取、負載均衡、Rewrite 舊網址等。
三、多站點架構:Host-Based 與 Path-Based Routing
1. Host-Based:多個網域或子網域
典型用法:一個 Nginx 對應多個服務,各自有不同網域。
# /etc/nginx/conf.d/app1.conf
server {
listen 80;
server_name app1.example.com;
location / {
proxy_pass http://10.0.10.21:8080;
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-Proto $scheme;
}
}
# /etc/nginx/conf.d/app2.conf
server {
listen 80;
server_name app2.example.com;
location / {
proxy_pass http://10.0.10.22:8080;
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-Proto $scheme;
}
}
2. Path-Based:同網域下切分應用路徑
另一種常見情境:全部都走 https://portal.example.com,但不同路徑對應不同服務。
# /etc/nginx/conf.d/portal.conf
server {
listen 80;
server_name portal.example.com;
# /app1 → 轉給內部 10.0.10.31
location /app1/ {
proxy_pass http://10.0.10.31:8080/;
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-Proto $scheme;
}
# /app2 → 轉給內部 10.0.10.32
location /app2/ {
proxy_pass http://10.0.10.32:8080/;
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-Proto $scheme;
}
# /grafana → Grafana 後端
location /grafana/ {
proxy_pass http://10.0.10.40:3000/;
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-Proto $scheme;
}
}
注意 location /path/ 與 proxy_pass 的結尾斜線關係,會影響 URL 被轉發時的路徑拼接方式,
若處理不當很容易出現 // 或路徑被吃掉的錯誤。建議在實際環境多做幾個對照測試。
四、Rewrite 與 URL 設計:return / rewrite / try_files
在做 Reverse Proxy 時,常常要處理舊網址導向、新舊 API 路徑切換、或是讓靜態網站框架(例如 SPA、前端 Router)正常工作, 這時候就會用到 Rewrite 與 Redirect。
1. 用 return 做簡單 301/302 導轉
# 將舊網址 /old-path 永久導向新網址 /new-path
location = /old-path {
return 301 /new-path;
}
# 將 http 全部導向 https(常見)
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
2. 用 rewrite 做路徑改寫(內部轉向)
# 將 /api/v1/... 改寫成 /v1/... 再交給後端(不改變瀏覽器位址列)
location /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://10.0.10.50:8080;
}
break 代表改寫完後在同一個 location 繼續處理,不再重新跑一次 location 匹配。
3. try_files:靜態檔案與 SPA 的好朋友
# 典型 SPA 前端設定:不存在的路徑都丟給 index.html
location / {
try_files $uri $uri/ /index.html;
}
為了避免出現 Redirect 迴圈與難以維護的 rewrite 規則, 一般建議的策略是:能用 return 的地方就用 return,只有需要內部改寫時才上 rewrite。
五、Nginx Proxy Cache:為後端減壓的快取層
Nginx 可以直接在 Reverse Proxy 層做 HTTP Cache,對於不常變動的 API 或靜態內容來說, 能大幅減少後端壓力與回應時間。
1. 定義快取區與 Key
# http 區段(通常在 nginx.conf)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:100m
max_size=10g inactive=60m use_temp_path=off;
說明:
keys_zone=my_cache:100m:快取索引儲存在記憶體中,約 100MB。max_size=10g:快取檔案最多使用 10GB 磁碟空間。inactive=60m:60 分鐘沒被訪問的 cache 會被清除。
2. 在 server / location 啟用 Cache
server {
listen 80;
server_name api.example.com;
location /v1/ {
proxy_pass http://10.0.20.10:8080;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
add_header X-Proxy-Cache $upstream_cache_status;
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-Proto $scheme;
}
}
之後你可以觀察 X-Proxy-Cache Header(例如 MISS / HIT / EXPIRED),
來判斷快取命中狀況。
六、Load Balancing:多台後端的流量分散策略
Nginx 的 upstream 模組可以讓你非常容易把流量分散到多台後端主機。
1. 基本 round-robin 負載均衡
# http 區段中定義 upstream
upstream app_backend {
server 10.0.30.11:8080;
server 10.0.30.12:8080;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://app_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-Proto $scheme;
}
}
2. least_conn、ip_hash 等策略
# 以連線數最少為優先(適合長連線或資源差異較大的後端)
upstream app_backend_least {
least_conn;
server 10.0.30.11:8080;
server 10.0.30.12:8080;
}
# 以 client IP 算 hash(簡易 session 黏著)
upstream app_backend_sticky {
ip_hash;
server 10.0.30.11:8080;
server 10.0.30.12:8080;
}
若你的應用對 Session 黏著度有要求(例如 Session 存在 local memory),
可以搭配 ip_hash 或改用外部 Session Store(Redis 等),就可以使用更平均的分流策略。
七、X-Forwarded-* 與 Header 處理:讓後端知道真實世界
Reverse Proxy 之後,後端看到的 Client IP 會變成 Nginx 的 IP,因此我們通常會透過標準 Header 把真實 Client 資訊帶進去:
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-Proto $scheme;
- X-Real-IP:記錄最接近 Client 的來源 IP。
- X-Forwarded-For:一條 Proxy 鏈路上的所有 IP。
- X-Forwarded-Proto:告訴後端原本是 HTTP 還是 HTTPS。
很多應用會依據這些 Header 來產生日誌、產生絕對網址、或判斷是否強制跳轉 HTTPS, 如果沒設定好,常出現「在 HTTPS 的前端,但後端以為是 HTTP」之類的怪異行為。
八、Timeout / Buffer / 限制值:避免莫名斷線與爆記憶體
在高延遲或後端查詢較慢的環境裡,如果 Proxy timeout 太短,就會看到大量 502/504。 常用參數包括:
# server 或 location 範圍皆可設定
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 控制 Nginx 接收上游回應的 buffer
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
在調整這些數值時,建議先理解後端應用的平均與最長處理時間,再預留合理空間,避免一味拉很長造成資源長時間被占用。
九、排錯與實戰心法:502/504、迴圈 Redirect、Header 問題
1. 502 / 504 錯誤
- 確認後端服務是否真的有在指定 IP/Port 上 listen。
- 檢查 Nginx error log 裡的詳細錯誤訊息(如
connect() failed、upstream timed out)。 - 調整
proxy_connect_timeout、proxy_read_timeout等參數。 - 確認 Security Group / 防火牆是否放行 Nginx 與後端之間的連線。
2. 無限 Redirect / URL 迴圈
- 常見於 HTTP→HTTPS、或應用程式內再轉一次 Redirect。
- 檢查應用是否依據
X-Forwarded-Proto判斷協定,若沒設好會以為自己在 HTTP 上再轉一次 HTTPS。 - 簡化 Rewrite 規則,能用
return就不用複雜的rewrite正則。
3. Client IP 都變成 Nginx 的 IP
- 確認有設定
X-Real-IP與X-Forwarded-For。 - 在後端 Web Server 或應用框架中,設定採用這些 Header 作為真實 IP 的來源。
- 如果有多層 Proxy,要做信任 Proxy 列表(避免偽造 Header)。
十、常見問題 FAQ
Q1. 什麼情況下適合在前端使用 Nginx Reverse Proxy?
只要你的架構中存在多個後端服務、需要集中控管對外入口、或者希望把 TLS、快取、Rewrite、存取控制集中處理, 幾乎都可以考慮在前端放一層 Nginx Reverse Proxy。特別是當你未來有計畫導入微服務或容器平台時, 這層入口會變得更加關鍵。
Q2. Nginx Reverse Proxy 和 Load Balancer 有什麼差別?
Nginx 本身既可以是 Reverse Proxy,也可以是 Load Balancer。概念上:
- Reverse Proxy:代表後端服務接收請求,處理 URL、Header、Cookie、壓縮、TLS 等邏輯。
- Load Balancer:專注在把流量分散到多台後端主機上。
很多實作會直接在同一台 Nginx 上同時做這兩件事,真正的差別比較偏向「架構角色」而非工具本身。
Q3. 要不要把靜態檔案直接放在 Nginx 上,而不是後端?
在多數情況下是值得的。將靜態檔案(圖片、CSS、JS、前端打包結果等)直接由 Nginx 提供,可以大幅減少後端負擔, 並且更容易設定 Cache-Control 與壓縮,不過你仍然需要考慮部署流程(如何同步檔案)與版本管理策略。
Q4. 要不要直接把快取與負載均衡都做在同一台 Nginx 上?
小型或單一區域的環境,可以用「一台 Nginx 做到底」的方式,維護簡單、成本低; 但在高流量、多地部署或高度關鍵系統中,通常會分層:L4 負載均衡、CDN 或專用快取層、L7 Reverse Proxy,再往後才是應用。
🧭 行動清單:如何把這些設定落地到你的環境?
✅ 先整理現有服務清單:有哪些網域 / 路徑 / 內部 IP / Port?
✅ 決定 Multisite 策略:以 Host 為主,還是以 Path 為主,或兩者混用?
✅ 在 Lab 或測試環境先搭一層 Nginx Reverse Proxy,驗證 Proxy / Rewrite / Header 行為
✅ 對靜態內容或可快取 API 啟用 Proxy Cache,觀察 Hit Rate 與後端負載變化
✅ 對負載較重的服務設計 upstream load balancing,搭配 least_conn 或 ip_hash
✅ 寫一份簡短的「排錯手冊」,包含常見 502/504、Redirect 迴圈、Client IP 問題的處理步驟
💬 一起分享你的 Nginx Reverse Proxy 架構
你目前的 Nginx Reverse Proxy 是怎麼設計的?
是單一前端 Gateway,還是搭配多層 Load Balancer 與 CDN?
在導入多站點、Rewrite、快取與負載均衡的過程中,有沒有踩過什麼有趣的坑?
歡迎在下方留言分享你的實戰經驗,也可以提出想看的延伸主題(例如與 Kubernetes Ingress、Service Mesh 的整合),
我會再整理成後續文章 🙌
🔗 延伸閱讀
- 🐧 Linux 實戰防禦:Firewalld、iptables 與 nftables 的整合策略與最佳安全架構
- 🐧 GoAccess 日誌分析:Nginx / Apache 即時流量儀表板建置教學
- 🐧 Linux OpenVPN Server 架設完整指南:PKI 憑證、雙向驗證與 Client 路由導向
- 🐧 Linux 安全架構深度解析:SELinux、AppArmor、auditd 與 Fail2Ban
- 🐧 Proxmox 虛擬網路全攻略:Linux Bridge、OVS 與 VXLAN 實戰設定
— WWFandy・Nginx Reverse Proxy 筆記
沒有留言: