伺服器管理必學 100 招|Part 5:Web 伺服器與反向代理
前言
在現代分散式與微服務架構中,Web 伺服器早已不只是拿來掛靜態 HTML。它是所有流量的第一道閘門,負責流量分流、SSL/TLS 終結、速率限制以及客戶端 IP 的精準透傳。本篇精選 10 個核心反向代理與 Web 伺服器實戰技巧,以業界標準 Nginx 為核心,帶你掌握從安全防護、效能壓縮到長連線代理的全套配置。
技巧 041:標準反向代理起手式:精準透傳客戶端真實 IP
- 痛點場景:
後端服務(如 Node.js、Python、Go)接收到的請求來源全是127.0.0.1,導致應用程式無法辨識使用者真實 IP,無法做風控、日誌記錄或地域判斷。 - 解決方案:
在 Nginx 的location區塊中配置標準 Header 透傳:
location / {
proxy_pass http://127.0.0.1:8000;
# 必備三劍客:透傳真實客戶端 IP 與協議
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;
}
- 若最外層還掛有 Cloudflare 或 CDN,需在
http區塊指定受信任 CDN 網段並啟用real_ip模組:
# 信任 Cloudflare IP 區段並替換真實來源
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;
- 專家提醒:
在後端框架讀取 IP 時,若前端有多層代理,務必優先信任由信任反向代理設定的X-Real-IP或解析過的X-Forwarded-For最左側值。
技巧 042:告別 413 錯誤!上傳大檔案必調的 client_max_body_size
- 痛點場景:
使用者在網站上傳圖片、影音或大檔案時,瀏覽器直接噴出413 Request Entity Too Large,請求甚至根本沒送達後端程式碼。 - 解決方案:
Nginx 預設限制上傳大小僅為1m。依專案需求在http、server或特定location區塊調高上限:
server {
listen 443 ssl http2;
server_name api.example.com;
# 限制單次請求 Body 上限為 50MB
client_max_body_size 50M;
# 避免傳輸大檔案時逾時
client_body_timeout 60s;
}
- 專家提醒:
若該站點只有/api/upload路由需要上傳大檔,建議將client_max_body_size限制在該location內部,避免惡意人士對全站其他 API 發送大量空 Body 消耗頻寬。
技巧 043:雙向長連線不中斷!WebSocket 代理升級配置
- 痛點場景:
部署 Socket.IO、FastAPI WebSocket 或即時通訊服務時,前端瀏覽器連線頻繁斷線或回退為長輪詢(Long Polling),終端出現WebSocket connection failed。 - 解決方案:
在 Nginx 設定中明確啟用協定升級標頭:
# 在 http 區塊定義升級條件映射
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name ws.example.com;
location /ws/ {
proxy_pass http://127.0.0.1:8080;
# WebSocket 握手升級協定
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 調高逾時門檻,防止閒置數十秒被強制掐斷(預設 60s)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
- 專家提醒:
proxy_read_timeout建議搭配應用層的心跳包(Ping/Pong 機制),否則防火牆或 NAT 閘道可能在幾分鐘內直接斷開假死連線。
技巧 044:防爬蟲與暴力刷庫!內建 Rate Limiting 限流防禦
- 痛點場景:
登入介面遭到大量帳密暴力破解,或是爬蟲每秒數百次狂打資料庫密集型 API,導致伺服器 CPU 瞬間破表。 - 解決方案:
利用 Nginx 原生的 Leaky Bucket(漏桶演算法)實施以 IP 為單位的存取速率管制:
# 在 http 區塊定義記憶體儲存區(命名為 api_limit,依 Client IP 追蹤,容量 10MB,基準速率每秒 5 次)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
server {
location /api/login {
# 套用限流規則:允許突發(burst)緩衝 10 次,不延遲處理
limit_req zone=api_limit burst=10 nodelay;
# 超過限流時回傳 HTTP 429(Too Many Requests)
limit_req_status 429;
proxy_pass http://127.0.0.1:8000;
}
}
- 專家提醒:
加上nodelay參數非常重要,它能讓合理的短暫突發請求立即被處理,而不會排隊造成客戶端嚴重卡頓。
技巧 045:傳輸頻寬節省 70%!配置 Gzip 與 Brotli 靜態壓縮
- 痛點場景:
前端打包後的巨大 JS/CSS 檔案(例如 3MB 的 vendor.js)未經壓縮直接傳輸,導致網頁首屏載入時間(FCP)過長,吃掉伺服器大量流量費用。 - 解決方案:
在http區塊開啟 Gzip 壓縮,並指定壓縮類型:
http {
gzip on;
gzip_vary on;
gzip_proxied any;
# 壓縮等級建議設為 5 或 6(兼顧 CPU 消耗與壓縮率)
gzip_comp_level 6;
# 小於 1KB 的檔案不壓縮,避免壓縮後反而變大
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/x-javascript
application/xml
application/xml+rss
image/svg+xml;
}
- 專家提醒:
千萬不要將圖片檔(JPG、PNG)或影片加入gzip_types,因為這些格式原本就是高壓縮二進制檔案,再壓只會白白浪費 CPU 運算資源。
技巧 046:瀏覽器快取最佳化:利用 Cache-Control 實現靜態資源極速載入
- 痛點場景:
每次使用者換頁或重新造訪,瀏覽器都重複向伺服器下載一模一樣的圖片、字型與 CSS 檔案,拖慢載入速度。 - 解決方案:
針對帶有雜湊值(Hash)的靜態資源配置長期快取標頭:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform, immutable";
access_log off; # 靜態資源不寫入 Access Log,節省磁碟 I/O
}
# 對於永遠不能被快取的 HTML 首頁
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
- 專家提醒:
配合現代前端建置工具(Vite / Webpack)檔名自帶 Hash(如app.a8f2c.js),加上immutable屬性能讓瀏覽器在 30 天內完全不發起驗證請求。
技巧 047:隱藏版本號與注入 HTTP 安全標頭(Security Headers)
- 痛點場景:
伺服器預設回傳的 Header 帶著Server: nginx/1.18.0 (Ubuntu),攻擊者能直接根據版號搜尋已知的未修補漏洞發起精準攻擊。 - 解決方案:
關閉版本顯示,並注入現代 Web 安全標頭防範 XSS 與點擊劫持(Clickjacking):
http {
# 隱藏 Nginx 版號資訊
server_tokens off;
# 防範點擊劫持(Clickjacking)
add_header X-Frame-Options "SAMEORIGIN" always;
# 阻止瀏覽器 MIME-type 嗅探攻擊
add_header X-Content-Type-Options "nosniff" always;
# 啟用 HSTS,強制瀏覽器在接下來 1 年內一律走 HTTPS 連線
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 參照來源策略保護使用者隱私
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
- 專家提醒:
啟用Strict-Transport-Security(HSTS)前,務必確認全站包含所有子網域皆已具備有效 SSL 憑證,一旦瀏覽器記錄該標頭,若憑證失效將完全無法降級訪問。
技巧 048:Upstream 負載平衡與健康檢查機制
- 痛點場景:
單台後端應用無法支撐高併發流量,需要水平擴充多台實例,並確保其中一台崩潰時,流量能無縫切換至其他節點。 - 解決方案:
使用upstream區塊定義後端叢集與容錯規則:
upstream backend_cluster {
# 輪詢機制搭配權重(Weight)
server 10.0.1.11:8000 weight=3;
server 10.0.1.12:8000 weight=2;
# 備援節點:僅在上述節點全掛時才接引流量
server 10.0.1.13:8000 backup;
# 健康檢查被動判斷:若 10 秒內失敗 2 次,暫停派發 30 秒
server 10.0.1.14:8000 max_fails=2 fail_timeout=30s;
# 保持向後端的長連線池(Keepalive),降低連線建置延遲
keepalive 32;
}
server {
location / {
proxy_pass http://backend_cluster;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 配合 upstream keepalive
}
}
- 專家提醒:
若系統需要保證「同一個使用者的請求固定派發給同一個後端」(Session Affinity),可在upstream頂部加入ip_hash;指令。
技巧 049:自訂優雅錯誤頁面(防止洩漏系統除錯資訊)
- 痛點場景:
後端程式當機時,Nginx 預設噴出冷冰冰且帶有系統特徵的502 Bad Gateway頁面,使用者體驗差且不專業。 - 解決方案:
配置內部攔截與優雅靜態錯誤頁面:
server {
# 當後端回傳 500, 502, 503, 504 時,由 Nginx 內部改寫導向自訂頁面
proxy_intercept_errors on;
error_page 500 502 503 504 /custom_50x.html;
location = /custom_50x.html {
root /var/www/error_pages;
internal; # 宣告為內部專用,外部無法直接透過 URL 訪問
}
}
- 專家提醒:
自訂錯誤頁面的 HTML 檔務必保持精簡,樣式與圖片建議使用 Base64 或內嵌 CSS,避免因為關聯的 CSS 檔案也載入失敗導致頁面跑版。
技巧 050:極簡主義替代方案:認識現代化 Caddy 自動 HTTPS 伺服器
- 痛點場景:
對於簡單的 Side Project 或輕量微服務,不想花時間寫複雜的 Nginx 設定檔、安裝 Certbot 以及設定自動續簽 Cron。 - 解決方案:
使用 Go 語言編寫的現代化伺服器 Caddy,一行設定檔自動搞定「反向代理 + 自動向 Let’s Encrypt 申請續簽 SSL」:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo apt install caddy -y
- 極簡
Caddyfile設定:
api.yourdomain.com {
reverse_proxy localhost:8000
}
-
啟動即用:
sudo systemctl restart caddy。
- 專家提醒:
只要將網域名稱 DNS 指向該伺服器 IP,Caddy 在啟動時會全自動完成 ACME 驗證、TLS 憑證簽發與自動續簽,非常適合中小規模專案快速上線。