如何減少nginx+wordpress+mysql架設在windows裡伺服器回應的等待時間(TTFB)

減少 Nginx、WordPress 和 MySQL 在 Windows 環境下的等待伺服器回應時間(TTFB),最核心的手段是升級 PHP 執行緒處理機制啟用 Nginx 頁面快取,並增加 MySQL 記憶體快取。以下是具體且針對 Windows 系統的優化步驟:

設定 Nginx 與 PHP 之間使用本地 IP

Windows 的網路機制(TCP/IP)在解析 localhost 時有時候會卡頓 1~2 秒。

  • 檢查 Nginx 設定:打開 nginx.conf,找到 fastcgi_pass 的地方。
  • 修改寫法:將 fastcgi_pass localhost:9000; 改為 fastcgi_pass 127.0.0.1:9000;。直接使用 IP 可以跳過 Windows 的主機名稱解析,現賺 0.5 秒回應時間。

啟用 Nginx FastCGI 頁面快取 (FastCGI Cache)

Windows 無法運行原生的 Linux PHP-FPM,多數情況下使用 php-cgi.exe 處理效能較弱,最有效降低回應時間的方式是讓 Nginx 直接把 PHP 算好的網頁存成靜態 HTML。

  • 設定方法:在 nginx.confhttp 區塊加入快取路徑(例如:fastcgi_cache_path c:/nginx/cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;)。
  • 套用快取:在 location ~ \.php$ 區塊中掛載此快取設定,以避免每次載入頁面都重新執行複雜的 PHP 與資料庫查詢。

在 Nginx 中,設定 FastCGI 快取(FastCGI Cache)必須分為兩個部分:

  1. 全域區塊 (http):使用 fastcgi_cache_path 定義快取的儲存路徑記憶體大小
  2. 伺服器區塊 (location ~ \.php$):使用 fastcgi_cache 啟用並套用剛剛定義的快取規則。

完整的 nginx.conf 檔如下

INI
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;	
    gzip  on;	
	
    # Sets the maximum allowed size of the client request body. 
    client_max_body_size 13M;	
	
    # 程式可執行的最長時間 (秒)
    fastcgi_read_timeout 60s;
    fastcgi_connect_timeout 60s;
	
    # ==========================================
    # 設定 FastCGI Cache 快取 (全域設定)
    # ==========================================
    # 定義快取:路徑設在 W 碟,快取名稱為 WORDPRESS,記憶體給 100M,7天沒人訪問就自動刪除
    # ※請確保 Windows 中已手動建立 W:/nginx/nginx-cache 資料夾
    fastcgi_cache_path W:/nginx/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=7d max_size=1g;
    
    # 定義快取的唯一識別 key 格式
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500 http_503;

    # ==========================================
    # WordPress 專用:定義哪些狀況要「跳過快取」
    # ==========================================
    map $request_method $skip_cache {
        POST 1;
        default 0;
    }
    map $query_string $skip_cache_query {
        "" 0;
        default 1;
    }
    # 結合多種條件判斷是否跳過快取
    # (後台、登入 Cookie、評論者、購物車等不快取)
    # 這裡在下方 server 區塊內會用 if 補強,確保後台安全

    # 1. 預設的 Localhost 伺服器
    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;
        charset utf-8;
        root   html;		
        access_log  logs/localhost.access.log;
        error_log   logs/localhost.error.log;

        location / {            
            index  index.php index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location ~ \.php$ {
            include        fastcgi.conf;
            include        fastcgi_params;

            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

            fastcgi_read_timeout 60s;
            fastcgi_connect_timeout 60s;			
        }
    }

    # 2. HTTP server: http://your_domain_name (純轉址)
    server {
        listen       80;
        server_name  your_domain_name;
        root   html/your_domain_name;
        
        # 修正:純轉址即可,不需要在這裡放 fastcgi_cache 參數,否則會報錯
        return 301 https://$host$request_uri;		
    }

    # 3. HTTPS server: https://your_domain_name (WordPress 主體)
    server {
        listen       443 ssl;
        charset utf-8;
        root         html/your_domain_name;
        access_log   logs/your_domain_name.access.log;
        error_log    logs/your_domain_name.error.log;
        index        index.php index.html index.htm;
        server_name  your_domain_name;

        # Windows 環境下,建議憑證路徑使用正斜線 /,避免 \ 被誤判為跳脫字元
        ssl_certificate      cert/://your_domain_name;
        ssl_certificate_key  cert/://your_domain_name;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        # ------------------------------------------
        # WordPress 快取排除邏輯 (必加,否則無法登入後台)
        # ------------------------------------------
        set $custom_skip_cache 0;

        # POST 請求與帶有參數的網址不快取
        if ($request_method = POST) { set $custom_skip_cache 1; }   
        if ($query_string != "") { set $custom_skip_cache 1; }   

        # 後台與特定頁面不快取
        if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
            set $custom_skip_cache 1;
        }
        
		   # 排除 WordPress 的 REST API,避免編輯器存檔時 JSON 出錯
		   if ($request_uri ~* "/wp-json/") {
			   set $custom_skip_cache 1;
		   }	
        # 已登入的使用者或留言者不快取
        if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
            set $custom_skip_cache 1;
        }

        location / {
            try_files $uri $uri/ /index.php?$args;
        }

        location = /favicon.ico {
            log_not_found off;
            access_log off;
        }

        # 靜態檔案快取(直接由 Nginx 處理,極速)
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
            expires max;
            log_not_found off;
            access_log off;
        }

        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
		
        # 處理 WordPress PHP 並啟用 FastCGI 快取
        location ~ \.php$ {            
            include        fastcgi.conf;
            include        fastcgi_params;
			
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
			
            # 啟用快取
            fastcgi_cache WORDPRESS;
			
            # 套用上面設定的排除邏輯
            fastcgi_cache_bypass $custom_skip_cache;
            fastcgi_no_cache $custom_skip_cache;
			
            # 快取時間設定
            fastcgi_cache_valid 200 301 302 1d;
            fastcgi_cache_valid 404 1m;	

			# 【核心關鍵:修正 MISS 的必加指令】
			# 告訴 Nginx 忽略 WordPress 或 WP-Optimize 塞進來的「不可快取」標頭
			# 這能強制將未登入訪客的 HTML 存進 W:/nginx/nginx-cache 
			fastcgi_ignore_headers Cache-Control Expires Set-Cookie;			

            # 在瀏覽器標頭加入快取狀態,方便 F12 檢驗
            add_header X-FastCGI-Cache $upstream_cache_status;
			
            fastcgi_read_timeout 60s;
            fastcgi_connect_timeout 60s;	
        }

        location ~ /\.(?!well-known).* {
            deny all;
        }
    }
}

核心參數重點解析(Windows 專屬注意)

  • W:/nginx/nginx-cache:這是快取檔案在 Windows 硬碟中的實體資料夾。請務必手動先去 W 碟建立好 nginxcache 這兩個資料夾,Nginx 不會自動建立多層目錄,如果找不到路徑會啟動失敗。
  • keys_zone=WORDPRESS:100m:這是幫這個快取取名字。100m 代表在記憶體(RAM)中開闢 100MB 的空間來存放「快取索引/金鑰」,100MB 足夠存放幾十萬個網頁的索引。
  • levels=1:2:建立兩層目錄結構來存放快取檔案,防止 Windows 單一資料夾內檔案太多導致檔案系統讀取變慢。

WordPress 必加的「跳過快取」設定(選用,但強烈建議)

如果您直接啟用快取,會導致一個嚴重問題:當您登入 WordPress 後台修改文章時,看到的還是舊的快取畫面;或者購物車、評論功能會出錯。

為了避免這種狀況,建議在 server 區塊內、location ~ \.php$ 之前,加入以下排除登入者與後台快取的邏輯:

INI
//nginx.conf

# 預設不跳過快取
set $skip_cache 0;

# POST 請求(送出表單、留言)不快取
if ($request_method = POST) {
    set $skip_cache 1;
}   
# 帶有參數的網址(搜尋、分頁等)不快取
if ($query_string != "") {
    set $skip_cache 1;
}   
# 後台網址、特定頁面不快取
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
    set $skip_cache 1;
}   
# 已經登入的會員、有留言過的人、有購物車的人不快取
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
    set $skip_cache 1;
}

# 然後在 location ~ \.php$ 區塊內,加入這兩行:
location ~ \.php$ {
    # ...(原有的 FastCGI 設定)...

		# 【核心關鍵:修正 MISS 的必加指令】
		# 告訴 Nginx 忽略 WordPress 或 WP-Optimize 塞進來的「不可快取」標頭
		# 這能強制將未登入訪客的 HTML 存進 W:/nginx/nginx-cache 
		fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
			    
    # 套用上面設定的排除邏輯(已登入、POST 等不快取)
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
}

套用此設定檔並重啟 Nginx 後,請嘗試用無痕視窗(未登入狀態)連續重新整理首頁兩次:

  • 第一次應該會顯示 X-FastCGI-Cache: MISS,第二次之後應該要顯示 X-FastCGI-Cache: HIT
  • 若有登入時, 顯示 X-FastCGI-Cache: BYPASS
  • 按下 F12 開啟開發者工具,切換到 Network (網路) 標籤頁。
  • 點擊第一個網頁請求(polinwei.com),查看 Response Headers

原理分析

  • WP-Optimize 的過度保護:許多優化外掛為了避免未登入的訪客「不小心看到別人的頁面」,會預設對網頁輸出 Cache-Control: private, must-revalidate 標頭。
  • Nginx 讀懂了它:Nginx 一旦看到後端 PHP 送來這個標頭,就會判定「這是不安全、不應該被快取的頁面」,因此不管您點幾次,Nginx 都會老老實實地去問 PHP(顯示 MISS)。
  • 解決之道:加入 fastcgi_ignore_headers 之後,Nginx 會把這些保護標頭「裝作沒看到」,並依照我們設定的 fastcgi_cache_valid 200 1d 強制將頁面寫入快取。因為我們前面有設定 $custom_skip_cache,所以已登入的管理者一樣很安全,不用擔心後台被快取到。

解決 Windows 獨有的 PHP-CGI 堵塞問題

在 Windows 上,Nginx 通常透過 php-cgi.exe 處理網頁。預設情況下,php-cgi.exe 一次只能處理一個請求,若同時有兩個人點擊網站,第二個人就必須「等待伺服器回應」。

  • 設定環境變數:在啟動 PHP 的批次檔(.bat)或系統環境變數中,加入 SET PHP_FCGI_CHILDREN=32(這會讓 PHP 允許最多 32 個平行緒)。
  • 防止自動崩潰:加入 SET PHP_FCGI_MAX_REQUESTS=2000(避免 PHP 記憶體洩漏崩潰,達到 2000 次請求後會自動重啟)。

優化 PHP-CGI 與連線數(php.ini)

因為 PHP 運行於 Windows 環境,需確保不會因為處理程序耗盡而讓瀏覽器排隊等待。

  • 開啟持久連線:修改 php.ini,設定 mysqli.allow_persistent = Onmysqli.max_persistent = -1,並允許 cgi.force_redirect = 1
  • 排程多程序:如果網站併發請求高,可利用 Nginx 的 upstream 功能,同時指向多個 php-cgi.exe 進行負載平衡來減少等待時間。

調整 MySQL 快取與記憶體設定 (my.ini)

MySQL 在 Windows 預設的記憶體分配極少,這會導致硬碟 I/O 頻繁,大幅增加讀取資料庫的時間。

  • InnoDB Buffer Pool:在 my.ini[mysqld] 區塊,將 innodb_buffer_pool_size 設置為您系統可用記憶體的 50% 左右(例如 8G 記憶體則設 4G),讓資料表與索引常駐 RAM。
  • 關閉查詢快取:較新版本的 MySQL 建議確保 query_cache_type = 0,以防多核心環境下因 Query Cache 產生的鎖定反而拖慢速度。

修改 MySQL my.ini 設定(直接吃滿記憶體)

Windows 預設的 MySQL 配置完全沒有發揮 16G 記憶體的優勢。請找到您的 my.ini 檔案,在 [mysqld] 區段下,將以下參數直接覆蓋或新增(建議先備份原檔案):

INI
[mysqld]
# 16G 記憶體,撥出 6G 專門給 MySQL 快取資料與索引
innodb_buffer_pool_size = 6G

# 增加日誌緩衝區,減少硬碟寫入頻率
innodb_log_buffer_size = 64M
innodb_log_file_size = 1G
innodb_flush_log_at_trx_commit = 2

# 調整每條連線使用的暫存記憶體(適度加大,避免寫入硬碟)
tmp_table_size = 64M
max_heap_table_size = 64M
read_buffer_size = 2M
read_rnd_buffer_size = 4M
sort_buffer_size = 4M

# 關閉效能低落的舊版查詢快取(MySQL 8.0 以下適用,8.0 以上可忽略此兩行)
query_cache_type = 0
query_cache_size = 0

修改後請務必重啟 MySQL 服務。

清理與優化 WordPress 自身資料庫

隨著網站運行時間拉長,過多的暫存資料會延長資料庫回應時間。

  • 清理無用資料:定期刪除舊文章修訂版、暫存資料(Transient)以及未使用的 Autoload 資料。
  • 最佳化資料表:進入 phpMyAdmin,全選 WordPress 資料表並執行「最佳化資料表 (Optimize Table)」動作。

外掛檢測與診斷

  • 安裝效能分析外掛:在 WordPress 網站安裝並啟用 Query Monitor,可以快速抓出是哪一個外掛、佈景主題或資料庫查詢導致伺服器回應遲緩。

優化 WP-Optimize 設定

WP-Optimize 是一個很好的整合型工具,請確保您開啟了以下關鍵核心功能:

  • 頁面快取 (Page Caching):進入 WP-Optimize > Cache,勾選 Enable page caching。這可以讓大部分訪客直接讀取快取檔案,不需要經過 MySQL 和 PHP 運算。
  • 資料庫自動清理:進入 WP-Optimize > Database,勾選「清除所有文章修訂版本」與「清除所有過期暫存資料 (Transients)」,並設定每週自動清理。

新文章發佈後, 未登入的用戶看不見新文章

這正是啟用 Nginx FastCGI 快取後最常遇到的「快取過期/未同步」問題。因為 Nginx 已經把舊的首頁與文章列表存成靜態 HTML(儲存在您的 W 碟),所以當您發布新文章時,未登入的訪客讀取的依然是 Nginx 舊的快取檔案,必須等到 1 天(1d)快取過期後才會看到新文章。

要徹底解決這個問題,有兩種最主流且推薦的解法:

解法一:安裝 WordPress 外掛,自動通知 Nginx 清理快取(最推薦、一勞永逸)

只要在 WordPress 安裝專門的快取清理外掛,每當您發布文章、修改文章、有新評論時,外掛就會自動刪除 Nginx 對應的快取檔案,未登入用戶就能瞬間看到更新。

  1. 安裝外掛:在 WordPress 後台搜尋並安裝 Nginx Helper
  2. 啟用與設定
    • 進入外掛設定頁面,勾選 Enable Purge
    • Purge Method (清理方式):請選擇 Using a Filesystem method(檔案系統直接刪除法)。
    • Cache Path (快取路徑):請填入您在 nginx.conf 設定的實體路徑:W:/nginx/nginx-cache
    • 下方的清理條件(Purge Conditions),建議勾選:發布新文章(Create)、修改文章(Update)、有新評論(Comment)。
  3. 成果:未來只要您一按「發布」,WordPress 就會直接去 W: 碟把受影響的快取檔案刪除,未登入訪客再次重新整理,Nginx 就會觸發 MISS 並重新抓取新文章變成全新的 HIT

解法二:如果您不想加外掛,縮短 Nginx 的快取有效時間

如果您不希望網站安裝太多外掛,可以透過修改 nginx.conf,將高頻率變動的頁面快取時間縮短(例如改為 10 分鐘或 1 小時),讓誤差縮小到使用者可接受的範圍。

請在 location ~ \.php$ 區塊中,修改原本的 fastcgi_cache_valid

INI
location ~ \.php$ {            
    # ... 其他設定保持不變 ...

    # 將原本的 1d (一天) 改為 10m (10分鐘) 或 1h (1小時)
    # 這樣就算不裝外掛,未登入用戶最慢 10 分鐘內一定能看到新文章
    fastcgi_cache_valid 200 301 302 10m;
    fastcgi_cache_valid 404 1m;			
    
    # ... 其他設定保持不變 ...
}

修改後記得重啟 Nginx 服務。


在還沒設定好上述自動化機制前,若急著讓訪客看到新文章,可以直接進入 Windows 的檔案總管,手動將 W:/nginx/nginx-cache/ 資料夾裡面的所有子資料夾與檔案全部刪除。這相當於手動清空 Nginx 全站快取,訪客重新整理就會立刻看到新文章。

建議可以先嘗試安裝 Nginx Helper,因為這是最不犧牲網站速度(依然維持高時效快取)又能解決同步問題的標準做法。

Nginx Helper 的最佳設定指南(Windows 專用)

安裝 Nginx Helper 後,請進入設定畫面並勾選以下核心選項:

  1. Enable Purge:勾選啟用。
  2. Purge Method:務必選擇 Using a Filesystem method(不要選 nginx fastcgi_cache_purge,因為 Windows Nginx 不支援)。
  3. Cache Path:輸入您在 nginx.conf 寫的絕對路徑:W:/nginx/nginx-cache
  4. Purge Conditions (自動清理條件)
    • 勾選 Modify post(修改文章)
    • 勾選 Create comment(有新留言時,讓未登入訪客看得見新留言)
    • 勾選 Delete post(刪除文章)

這樣一來,您一發布文章,外掛就會自動去 W 碟精準刪除首頁與該文章的快取,未登入的用戶就能在一秒內看到最新的文章,且完全不影響其他沒變動網頁的「超低回應時間(HIT)」。

您可以直接在 WordPress 後台搜尋並安裝 Nginx Helper

如果在啟用 Filesystem 模式時,外掛畫面上方出現紅色的「路徑無法寫入」或「找不到資料夾」的錯誤警告,這通常與 Windows 的斜線方向(/\)或系統權限有關。

Nginx Helper 檢查 RT_WP_NGINX_HELPER_CACHE_PATH 常數定義路徑中相符的快取檔案

這段文字是 Nginx Helper 外掛在設定畫面中,對於 Using a Filesystem method (檔案系統直接刪除法) 的官方繁體中文說明。它完美證實了這就是最適合您目前架構的方案。

既然您看到了這段說明,代表您已經進入了 Nginx Helper 的設定後台。請按照以下步驟完成最終對接,即可完美解決「未登入用戶看不到新文章」的問題:

修改 WordPress 的 wp-config.php

如說明所述,外掛需要讀取一個叫做 RT_WP_NGINX_HELPER_CACHE_PATH 的常數。請打開您 WordPress 根目錄底下的 wp-config.php 檔案,在 /* That's all, stop editing! Happy publishing. */ 這行字之前,加入以下這行程式碼:

PHP
/* Add any custom values between this line and the "stop editing" line. */

// 定義 Nginx Helper 尋找快取檔案的 Windows 實體路徑
define( 'RT_WP_NGINX_HELPER_CACHE_PATH', 'W:/nginx/nginx-cache' );

/* That's all, stop editing! Happy publishing. */

註:請確保路徑與您 nginx.conf 中的 fastcgi_cache_path 完全一致(建議使用正斜線 /)。

回到 WordPress 後台勾選設定

完成上述常數定義後,回到 Nginx Helper 設定頁面:

  1. Purge Method:勾選您剛剛讀到說明的那個選項(Using a Filesystem method)。
  2. Purge Conditions(清理條件):勾選 When a post is published (發布文章時)、When a post is edited (修改文章時)。
  3. 點擊 Save All Changes(儲存所有變更)。
image

設定能完美對接您的 Nginx

這段說明提到了兩個非常關鍵的條件,而您目前的 nginx.conf 已經全部完美命中:

  • 條件一:levels=1:2
    檢查 nginx.conffastcgi_cache_path W:/nginx/nginx-cache levels=1:2 ... (符合 ✅)
  • 條件二:fastcgi_cache_key "$scheme$request_method$host$request_uri"
    檢查 nginx.conffastcgi_cache_key "$scheme$request_method$host$request_uri"; (符合 ✅)

因為 Nginx 快取金鑰規格與外掛預設演算法完全相同,Nginx Helper 只要拿到 W:/nginx/nginx-cache 的路徑,它就能在您按下「發布文章」的瞬間,精準算出該文章在 W 碟裡的 MD5 快取檔名並直接將其刪除。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


內容索引