熱門分類
載入中…
目錄0%

🐧 Linux Nginx 反向代理實戰:HTTPS、負載平衡與後端服務整合

    🐧 Linux Nginx 反向代理實戰:HTTPS、負載平衡與後端服務整合

    在現代的網站與服務架構中,Nginx 反向代理(Reverse Proxy) 幾乎是標準配備。 不論是要統一管理 HTTPS 憑證、在多台後端之間做負載平衡、或將多種服務整合在同一個網域底下, Nginx 都能用簡潔的設定完成。

    本篇以 Linux 環境為主,從概念到實戰配置,完整介紹:

    • 什麼是「反向代理」?與「正向代理」有什麼不同?
    • 如何在 Linux 安裝與啟用 Nginx
    • 使用 Nginx 建立 HTTP/HTTPS 反向代理
    • 整合 Let's Encrypt 自動簽發免費憑證
    • 多台後端服務的負載平衡設定
    • 處理 WebSocket、REST API 等特殊情境
    • 常見問題與除錯技巧

    一、反向代理是什麼?與正向代理的差別

    1. 正向代理(Forward Proxy)

    正向代理是「站在用戶這一側」的代理伺服器:

    • 用戶直接連線到 Proxy,再由 Proxy 替用戶向網路上的網站發出請求。
    • 常見用途:公司內部上網控管、翻牆 Proxy、快取外部網站等。

    2. 反向代理(Reverse Proxy)

    反向代理則是「站在伺服器這一側」:

    • 外部用戶只看到反向代理的 IP / 網域。
    • 反向代理再根據路徑、Host、Header 等條件,把請求轉發給內部的後端服務。
    • 用戶完全不需要知道後端服務真正的 IP 或 Port。

    反向代理常見用途包括:

    • 集中管理 HTTPS(統一終結 TLS,後端走 HTTP)。
    • 多台後端服務的負載平衡(Load Balancing)。
    • 將多個應用(API、前端、後台)整合在同一個網域下。
    • 作為第一層防線:限制來源 IP、Rate Limit、基本 WAF 規則等。

    二、在 Linux 上安裝與啟動 Nginx

    以下示例以 Debian/Ubuntu 與 RHEL/CentOS 為主,其它發行版可對應各自的套件管理工具。

    1. Debian / Ubuntu

    sudo apt update
    sudo apt install -y nginx
    
    # 啟動與設定開機自動啟動
    sudo systemctl enable --now nginx
    
    # 檢查服務狀態
    sudo systemctl status nginx

    2. RHEL / CentOS / Rocky / AlmaLinux

    sudo dnf install -y nginx   # 舊版可用 yum
    sudo systemctl enable --now nginx
    sudo systemctl status nginx

    安裝後,如果防火牆有啟用,記得打開 HTTP/HTTPS:

    # 以 firewalld 為例
    sudo firewall-cmd --permanent --add-service=http
    sudo firewall-cmd --permanent --add-service=https
    sudo firewall-cmd --reload

    瀏覽器打開 http://伺服器IP,應該就會看到 Nginx 的預設歡迎頁面。


    三、基本 Nginx 結構與設定檔位置

    常見的 Nginx 目錄結構(以 Debian/Ubuntu 為例):

    • /etc/nginx/nginx.conf:主設定檔,會 include 其他 conf。
    • /etc/nginx/sites-available/:各站台設定(虛擬主機)。
    • /etc/nginx/sites-enabled/:實際啟用的站台設定(多用 symlink)。
    • /var/www/:預設網站根目錄。
    • /var/log/nginx/access.logerror.log:存放存取與錯誤紀錄。

    測試 Nginx 設定檔是否正確:

    sudo nginx -t       # 檢查語法
    sudo systemctl reload nginx    # 平滑重新載入設定

    四、HTTP 反向代理基本範例

    情境:Nginx 對外開放 80 port,後端有一個跑在 127.0.0.1:8080 的 Web 應用程式。

    1. 建立站台設定檔

    /etc/nginx/sites-available/myapp.conf 建立:

    server {
        listen 80;
        server_name example.com;
    
        # 可選擇記錄專用 log
        access_log /var/log/nginx/myapp_access.log;
        error_log  /var/log/nginx/myapp_error.log;
    
        location / {
            proxy_pass http://127.0.0.1:8080;
    
            # 保留真實 Client IP 與 Host
            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. 啟用站台

    # 建立 symlink 啟用
    sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
    
    # 測試設定並重新載入
    sudo nginx -t
    sudo systemctl reload nginx

    之後使用者只要連到 http://example.com,實際上就是由 Nginx 替他連到 127.0.0.1:8080


    五、HTTPS 與憑證管理:反向代理作為 TLS 終結點

    現代網站幾乎都要求使用 HTTPS,加上瀏覽器也會對 HTTP 顯示「不安全」警告。 最典型做法是讓 Nginx 負責 TLS 終結(Terminating TLS),後端維持 HTTP, 如此可集中管理憑證、減少後端負擔。

    1. 使用 Let's Encrypt + Certbot 自動簽發憑證

    # Debian / Ubuntu
    sudo apt install -y certbot python3-certbot-nginx
    
    # 透過 Nginx 外掛自動設定 HTTPS
    sudo certbot --nginx -d example.com -d www.example.com

    Certbot 會自動幫你:

    • 與 Let's Encrypt ACME 伺服器溝通。
    • 簽發憑證並存放到 /etc/letsencrypt
    • 修改對應的 Nginx server 區塊,加入 listen 443 ssl; 等設定。
    • 加入排程(systemd timer)自動續約。

    成功後設定檔會長得像這樣(簡化版):

    server {
        listen 80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name example.com www.example.com;
    
        ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
        location / {
            proxy_pass http://127.0.0.1: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;
        }
    }

    上面也示範了一個常見做法:所有 HTTP 80 連線一律 301 轉到 HTTPS


    六、多站台整合:同一台 Nginx 代理多個後端服務

    在實務中,常常會遇到一台主機上跑很多服務,例如:

    • 前端網站 https://www.example.com
    • API 伺服器 https://api.example.com
    • 後台管理介面 https://admin.example.com

    1. 依「網域」分流(vhost)

    可以為不同的 Host 建立不同 server 區塊:

    # 前端
    server {
        listen 443 ssl http2;
        server_name www.example.com;
    
        ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    
    # API
    server {
        listen 443 ssl http2;
        server_name api.example.com;
    
        ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

    2. 依「路徑」分流

    若只想使用同一個網域,也可以依照 URL 路徑轉發:

    server {
        listen 443 ssl http2;
        server_name example.com;
    
        # /api/* 轉給後端 API 伺服器
        location /api/ {
            proxy_pass http://127.0.0.1:8000/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    
        # /admin/* 轉給後台
        location /admin/ {
            proxy_pass http://127.0.0.1:9000/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    
        # 其他路徑當作前端網站
        location / {
            proxy_pass http://127.0.0.1:3000/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

    注意 proxy_pass 後面的「尾端斜線」有語意差異,會影響實際轉發的路徑。 一般情況下,建議「location 以 / 結尾,proxy_pass 也以 / 結尾」,保持一致較不易混亂。


    七、負載平衡:多台後端服務分流

    當單台後端服務承受不了流量時,就可以在 Nginx 前面加入負載平衡機制, 將請求分散到多台後端伺服器。

    1. 設定 upstream 區塊

    /etc/nginx/nginx.conf 或獨立 conf 裡定義:

    upstream myapp_backend {
        # 預設是 round-robin
        server 10.0.0.11:8080;
        server 10.0.0.12:8080;
    
        # 可以設計權重,例如:
        # server 10.0.0.11:8080 weight=2;
        # server 10.0.0.12:8080 weight=1;
    }

    2. 在 server 區塊中使用 upstream

    server {
        listen 443 ssl http2;
        server_name app.example.com;
    
        ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
    
        location / {
            proxy_pass http://myapp_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;
        }
    }

    3. 常見負載平衡策略

    • round-robin(預設):請求輪流分配到各後端。
    • least_conn:優先分配給目前連線數最少的後端。
    • ip_hash:由 Client IP 決定要連到哪一台,用於需要「會話黏著(sticky)」的服務。

    例如:

    upstream myapp_backend {
        least_conn;
        server 10.0.0.11:8080;
        server 10.0.0.12:8080;
    }

    八、特殊情境:WebSocket 與長連線服務

    一些現代 Web 應用會使用 WebSocket(例如即時聊天、即時監控), 或是需要長時間保持連線的 SSE(Server-Sent Events)。這類情況需要調整一些 proxy 相關參數。

    1. WebSocket 反向代理示例

    location /ws/ {
        proxy_pass http://127.0.0.1:7000;
    
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    2. 調整 Timeout,避免長連線被過早切斷

    proxy_read_timeout 3600;
    proxy_send_timeout 3600;

    實際值可依服務特性調整,避免過短造成連線頻繁重建,過長則可能浪費資源。


    九、安全強化與最佳實務

    反向代理擺在最前面,自然也是第一層安全防線,建議配合以下做法:

    1. 僅開放必要 Port

    • 對外只開 80/443,後端服務只聽 localhost 或內網 IP。
    • 配合 Linux 防火牆(iptables / nftables / firewalld)限制來源。

    2. 嚴格 HTTP Header 與大小限制

    # 限制請求體大小,避免被拿來上傳超大檔案
    client_max_body_size 10m;
    
    # 加入安全相關 Header(可依情況調整)
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    3. 使用 HTTP/2 與 TLS 強化設定

    在 listen 行加上 http2,並採用較新的 TLS 版本與 Cipher。

    4. 搭配 Fail2Ban 或 WAF

    可透過 log pattern 搭 Fail2Ban 進行簡易防禦,或導入如 ModSecurity 等 WAF 解決方案, 將惡意行為擋在反向代理這一層。


    十、常見問題與除錯技巧

    1. 502 Bad Gateway / 504 Gateway Timeout

    代表 Nginx 與後端服務間的溝通有問題,排查方向包括:

    • 後端服務是否有啟動?Port 是否正確?
    • Nginx 是否能連到後端 IP(防火牆、SELinux、容器網路…)。
    • 超時設定是否過短(proxy_read_timeout)。

    2. 靜態檔案路徑錯亂 / 重複的路徑前綴

    通常與 locationproxy_pass 的尾斜線有關。 若遇到問題,建議先簡化設定,只處理 / 路徑,再逐步拆出 /api、/admin 等子路徑。

    3. 真實 IP 沒有出現在後端 Log

    確認是否有設定:

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    並在後端 Web Server(例如 Apache、Node.js 應用)中設定使用此 Header, 取代直接讀取 remote_addr。

    4. 設定修改後卻沒有生效

    • 是否有將站台 conf 放到 sites-enabled(或 include 的目錄)?
    • 修改後是否有執行 nginx -tsystemctl reload nginx
    • 是否有多個相同 server_name 的 server 區塊互相衝突?

    十一、整理與延伸:把 Nginx 變成你的「統一入口」

    從實務角度來看,Nginx 反向代理可以幫你做到:

    • 對外只開一組 IP / 網域,內部服務完全藏在後面。
    • 集中管理 HTTPS 憑證(尤其搭配 Let's Encrypt 非常方便)。
    • 在多台後端之間分散流量,並簡化擴充流程。
    • 開始導入更進階的 DevOps 架構,例如容器化、微服務、Kubernetes 等。

    當你把常用的反向代理配置整理成 標準模板 之後, 不論是新專案上線、服務搬遷、或臨時增加測試環境, 只要複製一份 conf、調整幾個參數,就能快速完成。

    ✅ 建議下一步可以搭配:

    • Linux 防火牆與 Fail2Ban(限制來源 / 連線次數)。
    • 使用 Prometheus + Grafana 監控 Nginx 與後端服務狀態。
    • 將 Nginx 反向代理與 Docker / Proxmox 環境整合,作為整個內網服務的「入口閘道」。
    🔗 分享這篇 LINE Facebook X

    沒有留言:

    字級