# Cache WordPress bằng nginx: cấu hình FastCGI page cache đúng cách

> Hướng dẫn cache WordPress bằng nginx FastCGI cache: cấu hình, loại trừ trang đăng nhập và giỏ hàng, xoá cache khi cập nhật, kiểm tra HIT/MISS.

Source: https://zopanel.net/vi/blog/wordpress-page-cache-nginx  
Updated: 2026-10-21

## Ý chính

- Page cache của nginx lưu trang HTML đã tạo sẵn và trả cho khách tiếp theo mà không chạy PHP hay truy vấn database.
- Người đã đăng nhập, giỏ hàng, thanh toán, request POST và URL có query string phải luôn bỏ qua cache.
- Cần cơ chế xoá cache khi nội dung thay đổi, nếu không khách sẽ thấy bài cũ.
- Trong phép đo của chúng tôi, page cache nâng số website WordPress trên VPS 4 GB từ khoảng 100 lên 250.

Cache WordPress bằng nginx nghĩa là dùng **FastCGI cache** của nginx để lưu lại trang HTML mà WordPress đã tạo, rồi trả bản lưu đó cho những khách truy cập tiếp theo mà không cần chạy PHP hay truy vấn MySQL/MariaDB. Đây là cách tăng tốc WordPress hiệu quả nhất ở tầng server: trang được trả trong vài mili giây thay vì vài trăm mili giây, và cùng một VPS phục vụ được nhiều website hơn hẳn. Điều kiện để làm đúng là loại trừ người đã đăng nhập, giỏ hàng, thanh toán, và có cơ chế xoá cache khi nội dung thay đổi.

Bài này giải thích page cache hoạt động thế nào, cấu hình đầy đủ cho nginx trên Ubuntu 24.04 / Debian 12 (kèm lý do từng dòng), cách xoá cache, cách kiểm tra cache có thật sự chạy, và cách bật page cache trong ZoPanel.

## Page cache của nginx hoạt động thế nào?

Không có cache, mỗi lượt xem trang WordPress đều chạy toàn bộ chuỗi: PHP khởi động WordPress, nạp plugin và giao diện, gửi hàng chục truy vấn tới database, rồi dựng HTML. Việc đó tốn CPU và RAM, và lặp lại y hệt cho mọi khách đọc cùng một bài viết.

Với FastCGI cache, request đầu tiên vẫn đi qua PHP (gọi là **MISS**), nhưng nginx lưu kết quả xuống đĩa. Những request sau cho cùng URL được nginx trả thẳng từ cache (**HIT**); PHP và database không làm gì cả. Khi bản lưu hết hạn, nginx có thể trả bản cũ ngay cho khách trong lúc làm mới ở nền, nên không có chuyện hàng trăm khách cùng lúc kích hoạt PHP cho một trang vừa hết hạn.

## Page cache khác gì object cache, browser cache và CDN?

| Loại cache | Lưu cái gì | Ở đâu | Hữu ích nhất cho |
| --- | --- | --- | --- |
| Page cache (nginx FastCGI) | Nguyên trang HTML | Trên server, trước PHP | Khách chưa đăng nhập, blog, trang tin, landing page |
| Object cache (Redis) | Kết quả truy vấn database | Trong RAM, dùng bởi PHP | wp-admin, WooCommerce, người đã đăng nhập |
| OPcache | Mã PHP đã biên dịch | Trong RAM/đĩa | Mọi request có chạy PHP |
| Browser cache | Ảnh, CSS, JS | Trên máy khách | Lượt xem trang thứ hai trở đi |
| CDN | File tĩnh, có thể cả HTML | Máy chủ biên gần khách | Khách ở xa server, giảm tải băng thông |

Các lớp này bổ trợ cho nhau. Page cache cho hiệu quả lớn nhất với lượng khách chưa đăng nhập; object cache giúp phần còn lại, những trang không thể cache nguyên trang.

## Page cache giúp được bao nhiêu?

Chúng tôi đã đo trên VPS thật: một VPS Ubuntu 24.04 với 4 GB RAM và 4 vCPU chạy được **khoảng 100 website WordPress không có page cache, và 250 khi bật page cache**, cùng với 30 ứng dụng khác. Với VPS Debian 12 3 GB, con số là 50 và 200. Phương pháp đo, kiểu lưu lượng và giới hạn của các con số này nằm trong bài [VPS 4 GB chạy được bao nhiêu website WordPress](/vi/blog/how-many-wordpress-sites-4gb-vps). Website của bạn sẽ khác tuỳ plugin, lưu lượng và tỷ lệ khách đã đăng nhập.

## Cấu hình cache WordPress bằng nginx (làm tay)

Phần dưới giả định bạn đã có WordPress chạy với nginx và PHP-FPM (ví dụ PHP 8.3 qua socket `/run/php/php8.3-fpm.sock`). Hãy sao lưu cấu hình nginx trước khi sửa.

### Bước 1: Khai báo vùng cache

Tạo `/etc/nginx/conf.d/wordpress-cache.conf` (file trong `conf.d` nằm trong khối `http`):

```nginx
fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:64m
                   inactive=1d max_size=2g use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
```

- `keys_zone=WORDPRESS:64m` là vùng RAM lưu chỉ mục khoá; 1 MB chứa được khoảng tám nghìn khoá.
- `inactive=1d` xoá trang không ai xem trong một ngày.
- `max_size=2g` giới hạn dung lượng cache trên đĩa.
- Khoá cache gồm cả `$host`, nên nhiều website dùng chung một vùng cache không bị lẫn trang của nhau.

### Bước 2: Quy tắc không cache

Trong khối `server` của website, trước các `location`:

```nginx
set $skip_cache 0;

# Chỉ cache GET và HEAD
if ($request_method !~ ^(GET|HEAD)$) { set $skip_cache 1; }

# URL có query string (tìm kiếm, lọc, phân trang kiểu ?page=)
if ($query_string != "") { set $skip_cache 1; }

# Trang quản trị, đăng nhập, API, feed, sitemap, giỏ hàng, thanh toán
if ($request_uri ~* "/wp-admin/|/wp-login\.php|/wp-json/|/xmlrpc\.php|/feed/|sitemap|/cart/|/checkout/|/my-account/") {
    set $skip_cache 1;
}

# Người đã đăng nhập, người vừa bình luận, bài có mật khẩu, giỏ hàng WooCommerce
if ($http_cookie ~* "wordpress_logged_in|wp-postpass|comment_author|woocommerce_items_in_cart|wp_woocommerce_session") {
    set $skip_cache 1;
}
```

Dùng `if` chỉ để `set` biến như trên là cách dùng an toàn trong nginx. Nếu shop của bạn đổi đường dẫn giỏ hàng hay thanh toán (ví dụ `/gio-hang/`, `/thanh-toan/`), hãy thêm chúng vào danh sách.

### Bước 3: Bật cache cho PHP

Trong `location ~ \.php$` hiện có:

```nginx
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;

    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 200 301 10m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache_use_stale error timeout updating http_500 http_503;
    fastcgi_cache_background_update on;
    fastcgi_cache_lock on;
    add_header X-Cache $upstream_cache_status;
}
```

- `fastcgi_cache_valid 200 301 10m`: trang thành công được giữ 10 phút. Trang 404 hay lỗi không bị cache.
- `fastcgi_cache_bypass` và `fastcgi_no_cache`: không đọc và không ghi cache cho các request bị loại trừ ở bước 2.
- `use_stale updating` cùng `background_update`: khi trang hết hạn, khách vẫn nhận bản cũ ngay, một request ở nền làm mới. `error timeout http_500 http_503` còn cho phép trả bản cũ khi PHP đang lỗi, giúp website "sống" qua sự cố ngắn.
- `fastcgi_cache_lock`: nhiều request cùng lúc cho một trang chưa có trong cache chỉ tạo một request tới PHP.
- `X-Cache`: cho bạn thấy HIT, MISS hay BYPASS.

Lưu ý: `add_header` trong một `location` sẽ thay thế mọi `add_header` khai báo ở cấp `server` (ví dụ các header bảo mật). Nếu bạn có header ở cấp server, hãy lặp lại chúng trong location này. Chi tiết từng chỉ thị có trong [tài liệu module FastCGI của nginx](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html).

Tạo thư mục cache, kiểm tra và nạp lại cấu hình:

```bash
sudo mkdir -p /var/cache/nginx/wordpress
sudo nginx -t && sudo systemctl reload nginx
```

### Bước 4: Xoá cache khi nội dung thay đổi

Nếu không xoá cache, khách có thể thấy bài viết cũ tới 10 phút sau khi bạn sửa. Có ba cách:

1. **Thời gian cache ngắn** (vài phút) và chấp nhận độ trễ. Đơn giản nhất.
2. **Plugin Nginx Helper** cùng module `ngx_cache_purge`: plugin gửi yêu cầu xoá đúng những trang liên quan mỗi khi có bài mới, sửa bài hay bình luận. Trên Ubuntu 24.04 và Debian 12, module có sẵn trong gói `libnginx-mod-http-cache-purge`:

```bash
sudo apt install -y libnginx-mod-http-cache-purge
```

Thêm vào khối `server` một location chỉ cho phép chính server gọi:

```nginx
location ~ /purge(/.*) {
    allow 127.0.0.1;
    allow IP_CUA_SERVER;
    deny all;
    fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
}
```

Khoá trong lệnh purge phải khớp với `fastcgi_cache_key` ở bước 1. Sau đó cài [Nginx Helper](https://wordpress.org/plugins/nginx-helper/), bật purge và chọn phương thức dùng module `ngx_cache_purge`. Nếu thư mục cache khác mặc định của plugin, khai báo nó trong `wp-config.php` theo hướng dẫn của plugin.

3. **Xoá toàn bộ bằng tay** khi cần gấp: `sudo find /var/cache/nginx/wordpress -type f -delete`.

### Bước 5: Kiểm tra cache có thật sự chạy

Mở cửa sổ ẩn danh hoặc dùng curl (không có cookie đăng nhập), gọi cùng một URL hai lần:

```bash
curl -sI https://example.com/ | grep -i x-cache   # lần 1: MISS
curl -sI https://example.com/ | grep -i x-cache   # lần 2: HIT
```

Nếu lúc nào cũng là MISS hoặc BYPASS, nguyên nhân thường là:

- Một plugin gửi `Set-Cookie` trên mọi trang. Theo tài liệu nginx, response có `Set-Cookie` sẽ không được cache. Tìm plugin đó (thường là plugin thống kê, đa ngôn ngữ hoặc giỏ hàng) và cấu hình lại.
- WordPress hoặc plugin gửi header `Cache-Control: no-cache` hay `Expires` trong quá khứ.
- URL có query string, ví dụ link quảng cáo có `?utm_source=`.

## Bật page cache WordPress trong ZoPanel

ZoPanel có sẵn page cache của nginx cho mọi website PHP, đã gồm các quy tắc ở trên:

1. Mở website, vào tab **PHP & cấu hình**.
2. Bật **Page cache**.

Những gì được làm sẵn, theo tài liệu [Website và PHP](/vi/docs/hosting#page-cache):

- Trang được cache 10 phút; trang hết hạn được trả ngay trong khi một request làm mới ở nền; trang không ai dùng trong một ngày rời khỏi cache.
- Không bao giờ cache request khác GET và HEAD; khách có cookie đăng nhập WordPress, bài có mật khẩu, người bình luận, giỏ hàng hoặc session WooCommerce; các URL `/wp-admin`, `/wp-login.php`, `/wp-json`, `/xmlrpc.php`, `/cart`, `/checkout`, `/my-account`, `/feed`, sitemap; và URL có query string. Riêng query chỉ gồm tham số quảng cáo như `utm_*`, `fbclid`, `gclid` vẫn được tính là không có query, nên khách đến từ chiến dịch quảng cáo vẫn nhận trang đã cache.
- Website WordPress được cài một must-use plugin nhỏ tự xoá cache của website khi bài viết, bình luận, menu, giao diện hoặc plugin thay đổi. Nút **Xoá cache** xoá thủ công. Response có header `X-Cache`.
- Trang **Tối ưu** liệt kê các website WordPress chưa bật page cache và có nút **Áp dụng** để bật cho tất cả.

Với WooCommerce và website có nhiều người đăng nhập, bật thêm **Redis object cache** trong cùng tab: ZoPanel tạo một database Redis riêng cho website và cấu hình plugin. Xem thêm [WordPress Toolkit](/vi/docs/wordpress) và [Hiệu năng PHP](/vi/docs/php-performance). Lưu ý page cache tắt khi website dùng chế độ Apache.

## Những lỗi hay gặp khi cache WordPress bằng nginx

- **Cache trang của người đã đăng nhập**: khách khác thấy thanh quản trị hay thông tin tài khoản của người khác. Luôn kiểm tra cookie `wordpress_logged_in`.
- **Cache giỏ hàng và thanh toán**: khách thấy giỏ hàng của người khác. Loại trừ đúng các URL của shop bạn, kể cả khi đã đổi tên.
- **Không có cơ chế xoá cache**: khách thấy giá hay bài cũ.
- **Dùng thêm plugin page cache** (lưu file HTML ở tầng PHP) cùng với cache của nginx: hai lớp cùng loại khó xoá đồng bộ và khó tìm lỗi. Chọn một.
- **Giao diện khác nhau cho mobile và desktop** mà dùng chung khoá cache: khách mobile nhận bản desktop. Giao diện responsive không gặp vấn đề này.
- **Không kiểm tra `X-Cache`** sau khi cài: tưởng có cache nhưng thật ra mọi trang đều BYPASS.

## Kết luận

Cache WordPress bằng nginx là thay đổi đơn lẻ có tác động lớn nhất tới tốc độ và mật độ website trên một VPS: trang trả nhanh hơn, PHP và database nhẹ hơn, server chịu được đột biến lưu lượng tốt hơn. Phần khó là làm đúng: loại trừ đủ trường hợp, xoá cache khi nội dung đổi, và kiểm tra nó thật sự chạy. Nếu bạn muốn tất cả được làm sẵn cho mọi website, hãy thử [gói Free của ZoPanel](/vi/pricing) với 10 website và bật page cache chỉ bằng một công tắc.

## Câu hỏi thường gặp

### Cache WordPress bằng nginx có cần plugin không?

Không bắt buộc. FastCGI cache chạy hoàn toàn trong nginx. Plugin chỉ cần để xoá cache tự động khi nội dung thay đổi, ví dụ Nginx Helper cùng module ngx_cache_purge; nếu không, bạn đặt thời gian cache ngắn hoặc xoá bằng tay. ZoPanel tự cài một must-use plugin nhỏ cho việc xoá cache.

### Page cache có dùng được cho WooCommerce không?

Có, cho các trang sản phẩm và danh mục mà khách xem khi chưa thêm gì vào giỏ. Giỏ hàng, thanh toán, tài khoản và mọi khách đã có hàng trong giỏ phải bỏ qua cache. Shop có nhiều khách đăng nhập nên dùng thêm Redis object cache.

### Nên đặt thời gian cache bao lâu?

Nếu có cơ chế xoá cache khi cập nhật, 10 phút đến vài giờ là hợp lý, kết hợp làm mới ở nền. Nếu không có cơ chế xoá, hãy đặt vài phút để nội dung mới không bị trễ lâu.

### Làm sao biết trang đã được cache?

Xem header `X-Cache` của response bằng `curl -sI https://tenmien/ | grep -i x-cache` khi chưa đăng nhập. Lần đầu là MISS, lần sau là HIT. BYPASS nghĩa là request đó bị loại trừ theo quy tắc.

### Page cache của nginx và plugin như WP Super Cache, W3 Total Cache khác nhau thế nào?

Plugin cache vẫn để request đi qua PHP (hoặc dựa vào quy tắc rewrite để trả file HTML), còn FastCGI cache được nginx phục vụ trước khi PHP được gọi, nên nhẹ hơn ở mức server. Đừng chạy cả hai loại page cache cùng lúc; các tính năng khác của plugin (nén ảnh, gộp CSS) vẫn có thể dùng song song.
