Blog Details

Linux 作業系統 cutexyz > Blog > 伺服器管理 > 伺服器管理必學 100 招 > 伺服器管理必學 100 招|Part 5:Web 伺服器與反向代理

伺服器管理必學 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 憑證簽發與自動續簽,非常適合中小規模專案快速上線。