Nginx 作為現代 Web 架構的基石,以其卓越的效能表現、靈活的組態能力與豐富的功能特性,成為全球最受歡迎的 Web 伺服器與反向代理解決方案之一。相較於傳統的 Apache HTTP Server,Nginx 採用事件驅動的非同步架構,能夠以更少的系統資源處理更多的並發連線,特別適合高流量的 Web 應用場景。本文將深入探討 Nginx 的核心組態原理、效能調校技巧、安全性強化措施,以及與現代化開發工具的整合應用,協助讀者全面掌握 Nginx 在生產環境中的部署與管理。

Nginx 基礎架構與安裝部署

Nginx 的架構設計體現了其對高效能的追求。採用主從程序模型,由一個主程序管理多個工作程序,每個工作程序能夠處理數千個並發連線。這種設計充分利用了現代多核心處理器的運算能力,同時透過非阻塞的事件驅動機制,避免了傳統多執行緒模型的上下文切換開銷。

在 Debian 與 Ubuntu 系統上部署 Nginx 是一個相對直觀的過程。系統的套件管理工具提供了預先編譯好的 Nginx 套件,能夠快速完成安裝並自動處理依賴關係。然而,在生產環境中,我們需要對預設組態進行調整,以滿足特定的效能與安全需求。

# 更新套件索引確保取得最新版本資訊
sudo apt update

# 安裝 Nginx 主套件
sudo apt install -y nginx

# 啟動 Nginx 服務
sudo systemctl start nginx

# 設定開機自動啟動
sudo systemctl enable nginx

# 檢查 Nginx 服務狀態
sudo systemctl status nginx

# 驗證 Nginx 版本與編譯參數
nginx -v
nginx -V

# 測試組態檔語法正確性
sudo nginx -t

# 重新載入組態而不中斷服務
sudo nginx -s reload

Nginx 的主要組態檔位於 /etc/nginx/nginx.conf,這個檔案定義了全域性的伺服器行為。組態採用模組化的設計,透過 include 指令載入其他組態檔案,使得管理大型部署變得更加便利。典型的組態檔結構包含全域區塊、events 區塊與 http 區塊,每個區塊負責不同層面的設定。

# Nginx 主組態檔 /etc/nginx/nginx.conf

# 定義 Nginx 工作程序的執行使用者
# www-data 是 Debian/Ubuntu 系統的標準 Web 服務使用者
user www-data;

# 工作程序數量設定
# auto 會自動偵測 CPU 核心數並設定對應數量的工作程序
# 最佳化建議:通常設定為 CPU 核心數或稍少
worker_processes auto;

# 主程序 PID 檔案位置
pid /run/nginx.pid;

# 錯誤日誌檔案位置與記錄等級
# 等級選項: debug, info, notice, warn, error, crit
error_log /var/log/nginx/error.log warn;

# 載入動態模組
include /etc/nginx/modules-enabled/*.conf;

# Events 區塊定義連線處理機制
events {
    # 每個工作程序可處理的最大並發連線數
    # 理論最大並發數 = worker_processes * worker_connections
    worker_connections 2048;
    
    # 使用高效的事件模型(Linux 使用 epoll)
    use epoll;
    
    # 工作程序一次接受所有新連線
    multi_accept on;
}

# HTTP 區塊定義 Web 伺服器行為
http {
    
    ##
    # 基本設定
    ##
    
    # 載入 MIME 類型定義
    include /etc/nginx/mime.types;
    
    # 預設 MIME 類型
    default_type application/octet-stream;
    
    # 存取日誌格式定義
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    '$request_time $upstream_response_time';
    
    # 存取日誌檔案位置
    access_log /var/log/nginx/access.log main;
    
    ##
    # 效能最佳化設定
    ##
    
    # 啟用 sendfile 系統呼叫,提升靜態檔案傳輸效能
    sendfile on;
    
    # 與 sendfile 配合使用,減少網路封包數量
    tcp_nopush on;
    
    # 停用 Nagle 演算法,降低延遲
    tcp_nodelay on;
    
    # 持久連線超時時間
    keepalive_timeout 65;
    
    # 持久連線上的最大請求數
    keepalive_requests 100;
    
    # 請求標頭讀取超時
    client_header_timeout 30;
    
    # 請求主體讀取超時
    client_body_timeout 30;
    
    # 回應傳送超時
    send_timeout 30;
    
    # 客戶端請求主體最大尺寸
    client_max_body_size 20m;
    
    # 客戶端請求主體緩衝區大小
    client_body_buffer_size 128k;
    
    # 大型請求標頭緩衝區設定
    large_client_header_buffers 4 16k;
    
    ##
    # Gzip 壓縮設定
    ##
    
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript 
               application/json application/javascript application/xml+rss 
               application/rss+xml font/truetype font/opentype 
               application/vnd.ms-fontobject image/svg+xml;
    gzip_disable "msie6";
    
    ##
    # 快取設定
    ##
    
    # 開啟檔案快取
    open_file_cache max=10000 inactive=30s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
    
    ##
    # 安全性設定
    ##
    
    # 隱藏 Nginx 版本號
    server_tokens off;
    
    # 防止點擊劫持攻擊
    add_header X-Frame-Options "SAMEORIGIN" always;
    
    # 啟用 XSS 保護
    add_header X-XSS-Protection "1; mode=block" always;
    
    # 防止 MIME 類型嗅探
    add_header X-Content-Type-Options "nosniff" always;
    
    # 內容安全政策
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    
    ##
    # 虛擬主機組態
    ##
    
    # 載入站點組態檔案
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

這個組態檔展示了 Nginx 的核心設定結構。工作程序數量的自動偵測確保了系統資源的充分利用,而事件模型的選擇則直接影響並發處理能力。HTTP 區塊中的各項參數需要根據實際的硬體規格與流量模式進行調整,沒有一成不變的最佳值。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 140

package "Nginx 架構" {
  
  rectangle "主程序 (Master Process)" as master {
    component "組態管理" as config
    component "工作程序管理" as worker_mgmt
    component "訊號處理" as signal
  }
  
  package "工作程序池 (Worker Processes)" {
    rectangle "工作程序 1" as w1 {
      component "事件迴圈" as ev1
      component "請求處理" as req1
    }
    rectangle "工作程序 2" as w2 {
      component "事件迴圈" as ev2
      component "請求處理" as req2
    }
    rectangle "工作程序 N" as wn {
      component "事件迴圈" as evn
      component "請求處理" as reqn
    }
  }
  
  cloud "客戶端請求" as clients
  database "後端服務" as backend
}

clients --> w1
clients --> w2
clients --> wn

master --> w1
master --> w2
master --> wn

w1 --> backend
w2 --> backend
wn --> backend

@enduml

效能調校與資源最佳化

Nginx 的效能調校是一個系統性的工程,需要考慮網路層、應用層與作業系統層的多個面向。合理的參數設定能夠顯著提升系統的吞吐量與回應速度,同時降低資源消耗。效能調校的核心在於理解各個參數的作用機制,並根據實際的工作負載進行適配。

連線管理是效能調校的重要環節。持久連線機制允許客戶端在同一個 TCP 連線上發送多個 HTTP 請求,避免了頻繁的連線建立與關閉開銷。然而,過長的持久連線超時可能導致資源佔用,過短則無法充分發揮持久連線的優勢。在實務中,需要根據客戶端的請求模式找到平衡點。

# 高效能 Web 伺服器組態範例
# 適用於高流量生產環境

http {
    
    ##
    # 連線處理最佳化
    ##
    
    # 持久連線超時設定
    # 在高流量環境下,適度縮短超時可以釋放資源
    keepalive_timeout 30;
    
    # 單一持久連線上的最大請求數
    # 設定較高的值可以充分利用持久連線
    keepalive_requests 200;
    
    # 停用 IE6 的持久連線(已過時的瀏覽器)
    keepalive_disable msie6;
    
    # 緩慢關閉連線以確保資料完整傳輸
    lingering_close on;
    lingering_time 30s;
    lingering_timeout 5s;
    
    ##
    # 請求處理最佳化
    ##
    
    # 客戶端請求標頭讀取超時
    client_header_timeout 30;
    
    # 客戶端請求主體讀取超時
    client_body_timeout 30;
    
    # 忽略無效的請求標頭
    ignore_invalid_headers on;
    
    # 請求主體最大尺寸(根據應用需求調整)
    client_max_body_size 50m;
    
    # 請求主體緩衝區大小
    client_body_buffer_size 256k;
    
    # 大型請求標頭緩衝區(4 個 8KB 的緩衝區)
    large_client_header_buffers 4 8k;
    
    # 限制 Range 請求的範圍數量
    max_ranges 30;
    
    ##
    # 回應傳送最佳化
    ##
    
    # 回應傳送超時
    send_timeout 30;
    
    # 回應緩衝區設定
    # 關閉緩衝以減少記憶體使用(適合大檔案)
    proxy_buffering off;
    
    # 或者設定適當的緩衝區大小
    # proxy_buffer_size 4k;
    # proxy_buffers 8 4k;
    
    ##
    # FastCGI 最佳化(用於 PHP 等動態內容)
    ##
    
    # FastCGI 連線超時
    fastcgi_connect_timeout 60;
    
    # FastCGI 傳送超時
    fastcgi_send_timeout 180;
    
    # FastCGI 讀取超時
    fastcgi_read_timeout 180;
    
    # FastCGI 緩衝區設定
    fastcgi_buffer_size 64k;
    fastcgi_buffers 8 64k;
    fastcgi_busy_buffers_size 128k;
    
    # FastCGI 暫存檔案設定
    fastcgi_temp_file_write_size 256k;
    
    # FastCGI 快取設定(大幅提升動態內容效能)
    fastcgi_cache_path /var/cache/nginx/fastcgi 
                       levels=1:2 
                       keys_zone=fastcgi_cache:100m 
                       inactive=60m 
                       max_size=1g;
    
    ##
    # Proxy 快取最佳化
    ##
    
    # Proxy 快取路徑設定
    proxy_cache_path /var/cache/nginx/proxy 
                     levels=1:2 
                     keys_zone=proxy_cache:100m 
                     inactive=60m 
                     max_size=2g;
    
    # Proxy 快取鍵定義
    proxy_cache_key "$scheme$request_method$host$request_uri";
    
    # Proxy 快取有效期設定
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;
    
    ##
    # 限流與安全防護
    ##
    
    # 定義請求頻率限制區域
    # 限制每個 IP 每秒最多 10 個請求
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
    
    # 定義連線數限制區域
    # 限制每個 IP 最多 50 個並發連線
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    
    ##
    # 上游伺服器連線池(用於反向代理)
    ##
    
    upstream backend_servers {
        # 使用最少連線演算法進行負載平衡
        least_conn;
        
        # 啟用持久連線到上游伺服器
        keepalive 32;
        keepalive_requests 100;
        keepalive_timeout 60s;
        
        # 定義後端伺服器
        server backend1.example.com:8080 weight=3 max_fails=3 fail_timeout=30s;
        server backend2.example.com:8080 weight=2 max_fails=3 fail_timeout=30s;
        server backend3.example.com:8080 weight=1 max_fails=3 fail_timeout=30s backup;
    }
    
    ##
    # 虛擬主機範例
    ##
    
    server {
        listen 80;
        server_name example.com www.example.com;
        
        # 強制重導向到 HTTPS
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name example.com www.example.com;
        
        # 網站根目錄
        root /var/www/html;
        index index.html index.htm;
        
        # 套用請求頻率限制
        limit_req zone=req_limit burst=20 nodelay;
        
        # 套用連線數限制
        limit_conn conn_limit 50;
        
        # 靜態檔案處理
        location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
            expires 30d;
            add_header Cache-Control "public, immutable";
            access_log off;
        }
        
        # API 反向代理
        location /api/ {
            proxy_pass http://backend_servers;
            proxy_http_version 1.1;
            
            # 啟用到上游的持久連線
            proxy_set_header Connection "";
            
            # 轉發客戶端資訊
            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;
            
            # 啟用 Proxy 快取
            proxy_cache proxy_cache;
            proxy_cache_valid 200 10m;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            
            # 新增快取狀態標頭
            add_header X-Cache-Status $upstream_cache_status;
        }
    }
}

這個進階組態展示了多層次的效能最佳化策略。FastCGI 快取能夠顯著降低動態內容的生成開銷,對於 PHP 應用程式尤其有效。Proxy 快取則適用於反向代理場景,減少對後端服務的請求壓力。限流機制保護系統免受濫用,是生產環境必備的防護措施。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 130

start
:客戶端發送 HTTP 請求;
:Nginx 接收請求;
if (請求頻率限制檢查) then (通過)
  if (連線數限制檢查) then (通過)
    if (請求靜態資源?) then (是)
      :檢查檔案快取;
      if (快取有效?) then (是)
        :直接傳送快取內容;
      else (否)
        :讀取檔案系統;
        :建立快取;
        :傳送內容;
      endif
    else (否)
      if (需要 FastCGI 處理?) then (是)
        :檢查 FastCGI 快取;
        if (快取有效?) then (是)
          :傳送快取內容;
        else (否)
          :轉發到 FastCGI;
          :接收處理結果;
          :建立快取;
          :傳送內容;
        endif
      else (反向代理)
        :檢查 Proxy 快取;
        if (快取有效?) then (是)
          :傳送快取內容;
        else (否)
          :選擇後端伺服器;
          :轉發請求;
          :接收回應;
          :建立快取;
          :傳送內容;
        endif
      endif
    endif
  else (超過限制)
    :返回 503 錯誤;
  endif
else (超過限制)
  :返回 429 錯誤;
endif
:關閉連線或維持持久連線;
stop

@enduml

Docker 容器化部署整合

容器化技術徹底改變了應用程式的部署方式。將 Nginx 封裝為 Docker 容器,不僅簡化了部署流程,更提供了一致的執行環境,消除了「在我的電腦上可以運作」的經典問題。Docker 的輕量級特性使得 Nginx 容器能夠快速啟動,配合編排工具可以實現彈性的水平擴展。

Docker Compose 提供了宣告式的多容器應用定義方式。透過 YAML 檔案描述服務間的依賴關係、網路配置與資料卷掛載,使得複雜的部署變得簡單可重現。對於開發環境與測試環境,Docker Compose 是極佳的選擇,而在生產環境則可以無縫遷移到 Kubernetes 等容器編排平台。

# docker-compose.yml
# Nginx 容器化部署範例

version: '3.8'

services:
  
  nginx:
    # 使用官方 Nginx 映像檔
    image: nginx:1.25-alpine
    
    # 容器名稱
    container_name: nginx-server
    
    # 重啟策略
    restart: unless-stopped
    
    # 連接埠對映
    ports:
      - "80:80"
      - "443:443"
    
    # 資料卷掛載
    volumes:
      # 主組態檔
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      
      # 虛擬主機組態目錄
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      
      # 網站內容目錄
      - ./www:/var/www/html:ro
      
      # SSL 憑證目錄
      - ./nginx/ssl:/etc/nginx/ssl:ro
      
      # 日誌目錄(持久化)
      - nginx-logs:/var/log/nginx
      
      # 快取目錄(持久化)
      - nginx-cache:/var/cache/nginx
    
    # 環境變數
    environment:
      - TZ=Asia/Taipei
      - NGINX_HOST=example.com
      - NGINX_PORT=80
    
    # 網路設定
    networks:
      - web-network
    
    # 依賴服務
    depends_on:
      - php-fpm
      - redis
    
    # 健康檢查
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
  
  php-fpm:
    # PHP-FPM 容器(用於處理動態內容)
    image: php:8.2-fpm-alpine
    container_name: php-fpm
    restart: unless-stopped
    
    volumes:
      - ./www:/var/www/html:ro
      - ./php/php.ini:/usr/local/etc/php/php.ini:ro
    
    networks:
      - web-network
    
    environment:
      - TZ=Asia/Taipei
  
  redis:
    # Redis 容器(用於快取)
    image: redis:7-alpine
    container_name: redis-cache
    restart: unless-stopped
    
    command: redis-server --appendonly yes
    
    volumes:
      - redis-data:/data
    
    networks:
      - web-network
    
    environment:
      - TZ=Asia/Taipei

# 資料卷定義
volumes:
  nginx-logs:
    driver: local
  nginx-cache:
    driver: local
  redis-data:
    driver: local

# 網路定義
networks:
  web-network:
    driver: bridge

對應的 Nginx 組態檔需要針對容器環境進行調整。容器內的檔案路徑與主機不同,日誌輸出可以導向標準輸出以便於容器日誌管理系統收集。同時,需要確保 Nginx 能夠正確解析到其他容器的服務名稱。

# nginx/nginx.conf
# Docker 容器環境 Nginx 組態

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 2048;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format json_combined escape=json
        '{'
        '"time_local":"$time_local",'
        '"remote_addr":"$remote_addr",'
        '"request":"$request",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"request_time":$request_time,'
        '"http_referrer":"$http_referer",'
        '"http_user_agent":"$http_user_agent"'
        '}';
    
    access_log /var/log/nginx/access.log json_combined;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    
    keepalive_timeout 65;
    
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    
    # 載入虛擬主機組態
    include /etc/nginx/conf.d/*.conf;
}
# nginx/conf.d/default.conf
# 預設虛擬主機組態

# PHP-FPM 上游定義
upstream php_backend {
    server php-fpm:9000;
    keepalive 8;
}

server {
    listen 80;
    server_name localhost;
    
    root /var/www/html;
    index index.php index.html;
    
    # 健康檢查端點
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
    
    # 靜態檔案處理
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
    
    # PHP 檔案處理
    location ~ \.php$ {
        try_files $uri =404;
        
        fastcgi_pass php_backend;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        
        include fastcgi_params;
        
        fastcgi_connect_timeout 60s;
        fastcgi_send_timeout 180s;
        fastcgi_read_timeout 180s;
    }
    
    # 預設位置處理
    location / {
        try_files $uri $uri/ =404;
    }
}

使用 Docker Compose 啟動服務非常簡單,只需要一個命令就能夠完成整個堆疊的部署。容器間的網路連線由 Docker 自動處理,服務發現透過容器名稱即可實現。

# 啟動所有服務
docker-compose up -d

# 查看服務狀態
docker-compose ps

# 查看服務日誌
docker-compose logs -f nginx

# 重新載入 Nginx 組態
docker-compose exec nginx nginx -s reload

# 停止所有服務
docker-compose down

# 停止並移除資料卷
docker-compose down -v
@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 130

package "Docker 主機" {
  
  package "Web 網路 (Bridge)" {
    
    rectangle "Nginx 容器" as nginx {
      component "Nginx 主程序" as nginx_master
      component "工作程序" as nginx_workers
      folder "組態檔案 (唯讀掛載)" as nginx_conf
      folder "網站內容 (唯讀掛載)" as nginx_www
      folder "SSL 憑證 (唯讀掛載)" as nginx_ssl
    }
    
    rectangle "PHP-FPM 容器" as php {
      component "PHP-FPM 程序" as php_process
      folder "應用程式碼 (唯讀掛載)" as php_code
    }
    
    rectangle "Redis 容器" as redis {
      component "Redis 服務" as redis_service
      database "資料持久化" as redis_data
    }
  }
  
  cloud "外部請求" as client
  database "持久化資料卷" as volumes
}

client -down-> nginx : "HTTP/HTTPS\n連接埠 80/443"
nginx -down-> php : "FastCGI\n連接埠 9000"
nginx -down-> redis : "快取查詢\n連接埠 6379"
php -down-> redis : "Session 存儲"

nginx_conf -up-> volumes
nginx_www -up-> volumes
redis_data -up-> volumes

@enduml

SSL/TLS 安全性強化

在現代 Web 環境中,HTTPS 已經從可選項變為必要的基礎設施。SSL/TLS 協定不僅保護資料傳輸的機密性,更提供了伺服器身份驗證機制,防止中間人攻擊。搜尋引擎也將 HTTPS 作為排名因素之一,促使網站管理者採用加密連線。

Nginx 的 SSL/TLS 組態需要平衡安全性與相容性。最新的 TLS 1.3 協定提供了更強的安全性與更好的效能,但仍需要支援舊版協定以確保廣泛的客戶端相容性。加密套件的選擇也是關鍵,應該優先使用提供前向保密特性的套件,即使私鑰洩露也無法解密過去的通訊內容。

# SSL/TLS 安全組態範例
# /etc/nginx/conf.d/ssl-example.conf

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    
    server_name example.com www.example.com;
    
    ##
    # SSL 憑證設定
    ##
    
    # SSL 憑證檔案(完整憑證鏈)
    ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
    
    # SSL 私鑰檔案
    ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
    
    # 信任的 CA 憑證(用於 OCSP Stapling)
    ssl_trusted_certificate /etc/nginx/ssl/example.com/chain.pem;
    
    ##
    # SSL 協定與加密套件
    ##
    
    # 支援的 TLS 協定版本
    # 移除已不安全的 TLS 1.0 和 1.1
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # 優先使用伺服器端的加密套件順序
    ssl_prefer_server_ciphers on;
    
    # TLS 1.2 加密套件設定
    # 優先使用提供前向保密的 ECDHE 套件
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    
    # TLS 1.3 加密套件(通常使用預設值即可)
    # ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
    
    ##
    # DH 參數與 ECDH 曲線
    ##
    
    # Diffie-Hellman 參數檔案(用於 DHE 套件)
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    
    # ECDH 曲線設定
    ssl_ecdh_curve secp384r1;
    
    ##
    # SSL Session 快取
    ##
    
    # 共享 SSL Session 快取
    # 10MB 約可儲存 40000 個 Session
    ssl_session_cache shared:SSL:50m;
    
    # SSL Session 超時時間
    ssl_session_timeout 1d;
    
    # 啟用 SSL Session Tickets
    ssl_session_tickets on;
    
    # Session Ticket 金鑰檔案(定期輪替)
    ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
    
    ##
    # OCSP Stapling
    ##
    
    # 啟用 OCSP Stapling 減少客戶端憑證驗證延遲
    ssl_stapling on;
    
    # 驗證 OCSP 回應
    ssl_stapling_verify on;
    
    # DNS 解析器(用於 OCSP 查詢)
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    ##
    # 安全性標頭
    ##
    
    # HTTP 嚴格傳輸安全(HSTS)
    # 強制客戶端在指定時間內只使用 HTTPS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    
    # 防止點擊劫持
    add_header X-Frame-Options "SAMEORIGIN" always;
    
    # XSS 防護
    add_header X-XSS-Protection "1; mode=block" always;
    
    # MIME 類型嗅探防護
    add_header X-Content-Type-Options "nosniff" always;
    
    # 引用來源政策
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    
    # 內容安全政策
    add_header Content-Security-Policy "default-src 'self' https:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:; frame-ancestors 'self';" always;
    
    # 權限政策
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
    
    ##
    # 網站內容
    ##
    
    root /var/www/html;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

# HTTP 重導向到 HTTPS
server {
    listen 80;
    listen [::]:80;
    
    server_name example.com www.example.com;
    
    # Let's Encrypt ACME 挑戰
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    
    # 其他所有請求重導向到 HTTPS
    location / {
        return 301 https://$server_name$request_uri;
    }
}

使用 Let’s Encrypt 取得免費的 SSL 憑證是最佳實踐。Certbot 工具能夠自動化憑證的申請與更新流程,配合 Nginx 外掛可以自動完成組態調整。憑證的自動更新確保了持續的安全保護,避免因憑證過期導致服務中斷。

# 安裝 Certbot 與 Nginx 外掛
sudo apt install -y certbot python3-certbot-nginx

# 申請 SSL 憑證(自動組態 Nginx)
sudo certbot --nginx -d example.com -d www.example.com

# 測試自動更新
sudo certbot renew --dry-run

# 設定自動更新 Cron 任務
echo "0 0,12 * * * root certbot renew --quiet" | sudo tee -a /etc/crontab

# 生成 DH 參數檔案(提升安全性,但生成過程較耗時)
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

HSTS(HTTP Strict Transport Security)標頭指示瀏覽器在指定時間內只能透過 HTTPS 存取網站,即使使用者手動輸入 HTTP URL 也會自動轉換。includeSubDomains 指令將這個政策擴展到所有子網域,preload 則是準備將網站加入瀏覽器的 HSTS 預載入清單。

單頁應用與 API 閘道配置

單頁應用架構已成為現代 Web 開發的主流模式。React、Vue.js、Angular 等前端框架構建的應用程式,在客戶端透過 JavaScript 處理路由,而不是傳統的伺服器端路由。這要求 Nginx 的組態必須正確處理前端路由,避免將前端路由路徑誤判為不存在的檔案。

API 閘道模式將後端微服務隱藏在統一的入口之後。Nginx 作為反向代理,負責請求路由、負載平衡、快取與安全控管。這種架構分離了前端與後端的關注點,使得兩者可以獨立開發與部署,同時也簡化了跨域資源共享的處理。

# 單頁應用與 API 閘道組態範例
# /etc/nginx/conf.d/spa-api-gateway.conf

# 後端 API 服務定義
upstream api_backend {
    least_conn;
    
    server api1.internal.example.com:8080 max_fails=3 fail_timeout=30s;
    server api2.internal.example.com:8080 max_fails=3 fail_timeout=30s;
    server api3.internal.example.com:8080 max_fails=3 fail_timeout=30s backup;
    
    keepalive 32;
}

# WebSocket 服務定義
upstream websocket_backend {
    server ws1.internal.example.com:8081;
    server ws2.internal.example.com:8081;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;
    
    # SSL 設定(參考前面的 SSL 組態)
    ssl_certificate /etc/nginx/ssl/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/app.example.com/privkey.pem;
    
    # 單頁應用根目錄
    root /var/www/spa;
    index index.html;
    
    ##
    # SPA 前端路由處理
    ##
    
    location / {
        # 嘗試尋找檔案,若不存在則返回 index.html
        # 讓前端 JavaScript 路由器處理
        try_files $uri $uri/ /index.html;
        
        # 快取控制(針對 index.html 不快取)
        location = /index.html {
            add_header Cache-Control "no-cache, no-store, must-revalidate";
            add_header Pragma "no-cache";
            add_header Expires "0";
        }
        
        # 靜態資源長期快取
        location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
            access_log off;
        }
    }
    
    ##
    # API 反向代理
    ##
    
    location /api/ {
        # 套用限流保護
        limit_req zone=req_limit burst=20 nodelay;
        
        # 移除 /api 前綴並轉發到後端
        rewrite ^/api/(.*) /$1 break;
        
        proxy_pass http://api_backend;
        proxy_http_version 1.1;
        
        # 維持到後端的持久連線
        proxy_set_header Connection "";
        
        # 轉發客戶端資訊
        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;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        
        # 超時設定
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # CORS 標頭設定(如果需要)
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;
        add_header Access-Control-Allow-Credentials "true" always;
        
        # 處理 OPTIONS 預檢請求
        if ($request_method = 'OPTIONS') {
            return 204;
        }
        
        # 錯誤頁面
        proxy_intercept_errors on;
        error_page 502 503 504 = @api_error;
    }
    
    ##
    # WebSocket 支援
    ##
    
    location /ws/ {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        
        # WebSocket 升級標頭
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # WebSocket 超時設定(較長)
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
    }
    
    ##
    # 錯誤處理
    ##
    
    location @api_error {
        default_type application/json;
        return 502 '{"error": "Service temporarily unavailable", "code": 502}';
    }
    
    # 404 錯誤頁面
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
    
    # 50x 錯誤頁面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        internal;
    }
}

這個組態展示了完整的 SPA 與 API 閘道整合方案。try_files 指令確保所有前端路由都能正確處理,而 API 請求則透過反向代理轉發到後端服務。CORS 標頭的設定允許跨域請求,OPTIONS 預檢請求的特殊處理確保了 CORS 機制的正常運作。

WebSocket 支援需要特別的組態。Upgrade 和 Connection 標頭的正確設定是 WebSocket 連線建立的關鍵。相較於一般 HTTP 請求,WebSocket 連線的生命週期可能很長,因此需要設定較長的超時時間。

進階主題與最佳實踐

在生產環境中部署 Nginx 還需要考慮監控、日誌分析、自動化部署等多個面向。完善的監控系統能夠及時發現效能瓶頸與異常狀況,日誌分析提供了流量洞察與安全審計的基礎,而自動化部署則確保了變更的快速與可靠執行。

GoAccess 是一款開源的即時日誌分析工具,能夠解析 Nginx 的存取日誌並生成豐富的統計報告。它支援終端機介面與 HTML 報告兩種輸出方式,可以快速了解網站的流量模式、訪客來源、熱門頁面等資訊。對於需要即時監控的場景,GoAccess 的 WebSocket 模式能夠實現儀表板的自動更新。

# 安裝 GoAccess
sudo apt install -y goaccess

# 即時分析 Nginx 存取日誌(終端機模式)
goaccess /var/log/nginx/access.log \
    --log-format=COMBINED \
    --real-time-html

# 生成靜態 HTML 報告
goaccess /var/log/nginx/access.log \
    --log-format=COMBINED \
    --output=/var/www/html/report.html

# 啟動即時 HTML 儀表板
goaccess /var/log/nginx/access.log \
    --log-format=COMBINED \
    --real-time-html \
    --output=/var/www/html/report.html \
    --daemonize \
    --port=7890 \
    --ws-url=wss://example.com:7890

# 分析壓縮的日誌檔案
zcat /var/log/nginx/access.log.*.gz | goaccess \
    --log-format=COMBINED \
    --output=/var/www/html/report.html

持續整合與持續部署是現代軟體開發的核心實踐。Jenkins 與 GitLab CI/CD 都提供了強大的自動化能力,能夠在程式碼變更時自動觸發建置、測試與部署流程。整合 Nginx 組態的自動化部署需要確保語法驗證、漸進式推送與快速回復機制。

# .gitlab-ci.yml
# GitLab CI/CD 自動化部署 Nginx 組態

stages:
  - validate
  - test
  - deploy

variables:
  NGINX_CONFIG_PATH: "./nginx"
  DEPLOY_HOST: "production.example.com"

# 組態語法驗證
validate:nginx:
  stage: validate
  image: nginx:alpine
  script:
    - nginx -t -c ${NGINX_CONFIG_PATH}/nginx.conf
  only:
    changes:
      - nginx/**/*

# 安全性掃描
test:security:
  stage: test
  image: ubuntu:latest
  script:
    - apt-get update && apt-get install -y ssl-cert
    - |
      # 檢查 SSL 組態
      if grep -r "ssl_protocols.*TLSv1\." ${NGINX_CONFIG_PATH}; then
        echo "發現不安全的 TLS 協定版本"
        exit 1
      fi
  only:
    changes:
      - nginx/**/*

# 部署到生產環境
deploy:production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client rsync
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan ${DEPLOY_HOST} >> ~/.ssh/known_hosts
  script:
    - |
      # 同步組態檔案
      rsync -avz --delete \
        ${NGINX_CONFIG_PATH}/ \
        deploy@${DEPLOY_HOST}:/tmp/nginx-config/
      
      # 在遠端主機上執行部署
      ssh deploy@${DEPLOY_HOST} << 'EOF'
        # 備份當前組態
        sudo cp -r /etc/nginx /etc/nginx.backup.$(date +%Y%m%d%H%M%S)
        
        # 複製新組態
        sudo cp -r /tmp/nginx-config/* /etc/nginx/
        
        # 驗證組態
        sudo nginx -t
        
        # 重新載入 Nginx
        sudo systemctl reload nginx
        
        # 清理臨時檔案
        rm -rf /tmp/nginx-config
      EOF
  only:
    - main
  when: manual
  environment:
    name: production
    url: https://example.com

Nginx 的強大不僅體現在其卓越的效能,更在於其靈活的組態能力與豐富的生態系統。從基礎的 Web 伺服器功能到複雜的微服務閘道,從簡單的靜態內容服務到動態內容快取,Nginx 都能夠勝任。透過合理的組態調校,Nginx 能夠在有限的硬體資源下支撐大規模的流量,同時保持低延遲的回應速度。

玄貓認為,掌握 Nginx 的關鍵在於理解其工作原理而非死記組態參數。每個參數都有其存在的理由與適用場景,盲目複製他人的組態往往無法達到最佳效果。生產環境的組態應該是經過反覆測試與調整的結果,需要根據實際的硬體規格、流量模式與業務需求進行客製化。

安全性是永遠不能妥協的領域。即使犧牲一些效能,也應該確保 SSL/TLS 組態的安全性,定期更新 Nginx 版本以修補已知漏洞,實施適當的存取控制與限流機制。同時,完善的監控與日誌系統能夠在問題發生時快速定位,甚至在問題擴大前就發現潛在的隱患。

隨著容器化與雲端原生技術的普及,Nginx 的使用模式也在不斷演進。Kubernetes Ingress Controller、Service Mesh 等新興技術正在重新定義反向代理的角色。然而,Nginx 的核心價值始終不變,那就是提供高效能、高可靠性的 HTTP 流量處理能力。對於任何需要建構現代化 Web 服務的團隊而言,深入掌握 Nginx 都是一項值得投資的技能。