NGINX caching giảm CPU 80% cho WordPress / Laravel

Tài liệu » Quản trị VPS - Server » NGINX caching giảm CPU 80% cho WordPress / Laravel

Vì sao cần NGINX caching ngay?

Traffic tăng đột biến khiến server “quay cuồng”? 🤯 Trang web tải chậm như rùa, người dùng bỏ đi hết? 🐢 Bạn đang tốn kém chi phí cho server mạnh hơn nhưng hiệu quả không như ý? 💸 NGINX caching chính là “vị cứu tinh” bạn cần!

  • 🚀 Tăng tốc độ tải trang: Giảm thời gian phản hồi, mang lại trải nghiệm mượt mà.
  • 💪 Giảm tải CPU/RAM: Giải phóng tài nguyên, server chạy “nhẹ như lông hồng”.
  • 💰 Tiết kiệm chi phí hosting: Tối ưu hiệu suất, không cần nâng cấp server liên tục.
  • 📈 Cải thiện SEO: Tốc độ là yếu tố quan trọng, giúp website lên top Google dễ dàng hơn.
  • 🛡️ Chịu tải tốt hơn: Sẵn sàng đối mặt với lượng truy cập lớn mà không bị sập.

Hiểu về NGINX caching

Tóm gọn: NGINX caching lưu trữ các bản sao của nội dung tĩnh và động, giúp phục vụ yêu cầu nhanh hơn mà không cần xử lý lại từ đầu.

Các loại caching cơ bản của NGINX

NGINX cung cấp nhiều cấp độ caching, từ đơn giản đến nâng cao.

  • Browser Caching: Yêu cầu trình duyệt lưu trữ tài nguyên (CSS, JS, ảnh) cục bộ.
  • Proxy Caching: NGINX đóng vai trò proxy, lưu trữ phản hồi từ backend server (PHP-FPM, Gunicorn). Đây là loại caching chính chúng ta sẽ tập trung vào.

Cách NGINX lưu trữ dữ liệu

NGINX sử dụng một hệ thống thư mục để lưu trữ các tệp cache.

  • proxy_cache_path: Định nghĩa đường dẫn và các tùy chọn cho bộ nhớ cache.
  • levels: Cấu trúc thư mục cache (ví dụ: levels=1:2).
  • keys_zone: Đặt tên cho vùng bộ nhớ chia sẻ để lưu trữ metadata cache.
  • max_size: Kích thước tối đa của bộ nhớ cache.
  • inactive: Thời gian một mục cache được coi là “không hoạt động”.
  • use_temp_path=off: Tránh ghi vào thư mục tạm, giảm I/O.
# Ví dụ cấu hình proxy_cache_path
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
  • /var/cache/nginx: Thư mục lưu trữ cache.
  • levels=1:2: Tạo cấu trúc thư mục a/b/ để phân tán file.
  • my_cache:10m: Vùng bộ nhớ chia sẻ tên my_cache, dung lượng 10MB.
  • max_size=10g: Giới hạn kích thước cache là 10GB.
  • inactive=60m: Xóa cache không truy cập trong 60 phút.
  • use_temp_path=off: Tối ưu ghi file cache.

💡 Mẹo: Nên tạo thư mục /var/cache/nginx và cấp quyền ghi cho user NGINX (thường là www-data).

bash
sudo mkdir -p /var/cache/nginx
sudo chown www-data:www-data /var/cache/nginx
sudo chmod 700 /var/cache/nginx

Cấu hình NGINX proxy caching cho WordPress

Tóm gọn: Cấu hình NGINX để cache các phản hồi từ PHP-FPM, giảm đáng kể thời gian xử lý cho WordPress.

Bước 1: Định nghĩa proxy_cache_path

Thêm cấu hình proxy_cache_path vào file nginx.conf hoặc một file cấu hình riêng trong conf.d.

# /etc/nginx/nginx.conf hoặc /etc/nginx/conf.d/cache.conf
http {
    # ... các cấu hình http khác ...

    proxy_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=wp_cache:20m max_size=5g inactive=60m use_temp_path=off;

    # ...
}
  • wp_cache:20m: Vùng cache cho WordPress, dung lượng 20MB.
  • max_size=5g: Giới hạn cache 5GB, phù hợp với lượng ảnh và file tĩnh của WP.

Bước 2: Kích hoạt caching trong server block

Áp dụng caching cho các yêu cầu WordPress.

# /etc/nginx/sites-available/your-wordpress-site.conf
server {
    listen 80;
    server_name your-domain.com;
    root /var/www/wordpress;
    index index.php index.html index.htm;

    # Cấu hình cache
    set $cache_bypass 0;

    # Không cache các yêu cầu POST, AJAX, hoặc có cookie
    if ($request_method = POST) {
        set $cache_bypass 1;
    }
    if ($http_cookie ~* "comment_author|wordpress_logged_in|wp-postpass") {
        set $cache_bypass 1;
    }
    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|/cart/|/checkout/") {
        set $cache_bypass 1;
    }

    # Sử dụng cache nếu không bị bypass
    add_header X-Cache-Status $upstream_cache_status;
    proxy_cache wp_cache;
    proxy_cache_valid 200 302 10m;     # Cache 10 phút cho status 200, 302
    proxy_cache_valid 404 1m;          # Cache 1 phút cho status 404
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
    proxy_ignore_headers Cache-Control Expires Set-Cookie; # Bỏ qua header từ backend ảnh hưởng cache

    # Cấu hình FastCGI cho PHP
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Thay đổi theo version PHP của bạn

        # Truyền biến cache bypass cho PHP-FPM nếu cần
        fastcgi_param CACHE_BYPASS $cache_bypass;
    }

    # Các quy tắc khác (ví dụ: cho file tĩnh)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public";
    }

    location ~ /\.ht {
        deny all;
    }
}
  • set $cache_bypass 0;: Biến khởi tạo, mặc định cho phép cache.
  • Các lệnh if kiểm tra các điều kiện để không cache (ví dụ: yêu cầu POST, có cookie admin).
  • add_header X-Cache-Status $upstream_cache_status;: Thêm header để kiểm tra trạng thái cache (HIT, MISS, EXPIRED…).
  • proxy_cache wp_cache;: Kích hoạt cache sử dụng vùng wp_cache đã định nghĩa.
  • proxy_cache_valid: Thiết lập thời gian cache cho từng mã trạng thái HTTP.
  • proxy_cache_key: Định nghĩa khóa duy nhất cho mỗi mục cache.
  • proxy_cache_use_stale: Cho phép NGINX trả về cache cũ nếu backend gặp lỗi.
  • proxy_ignore_headers: Quan trọng để ghi đè các header từ backend có thể ngăn cache.
  • location ~ \.php$: Cấu hình cho các file PHP, truyền biến $cache_bypass nếu cần xử lý logic phía PHP.

⚠️ Cảnh báo: Nếu bạn sử dụng plugin caching cho WordPress (W3 Total Cache, WP Super Cache), hãy tắt chức năng page cache của chúng để tránh xung đột với NGINX caching.

Bước 3: Kiểm tra cấu hình

Sau khi áp dụng cấu hình, hãy kiểm tra xem NGINX có hoạt động đúng không.

sudo nginx -t

Nếu kết quả là syntax is oktest is successful, bạn có thể reload NGINX.

sudo systemctl reload nginx

Truy cập website của bạn, mở Developer Tools (F12), vào tab Network. Kiểm tra header X-Cache-Status. Lần truy cập đầu tiên sẽ là MISS, các lần sau (nếu không bị bypass) sẽ là HIT.

Cấu hình NGINX proxy caching cho Laravel

Tóm gọn: Laravel yêu cầu cấu hình cache khác biệt do tính chất ứng dụng web phức tạp hơn WordPress.

Bước 1: Định nghĩa proxy_cache_path (Tương tự WordPress)

Sử dụng proxy_cache_path như đã mô tả ở phần WordPress, nhưng có thể điều chỉnh keys_zonemax_size cho phù hợp.

# /etc/nginx/nginx.conf hoặc /etc/nginx/conf.d/cache.conf
http {
    # ...

    proxy_cache_path /var/cache/nginx/laravel levels=1:2 keys_zone=laravel_cache:30m max_size=10g inactive=30m use_temp_path=off;

    # ...
}
  • laravel_cache:30m: Vùng cache cho Laravel, dung lượng 30MB.
  • max_size=10g: Giới hạn cache 10GB.
  • inactive=30m: Thời gian cache không hoạt động là 30 phút.

Bước 2: Cấu hình NGINX cho Laravel (Sử dụng PHP-FPM)

Nếu Laravel của bạn chạy qua PHP-FPM.

# /etc/nginx/sites-available/your-laravel-site.conf
server {
    listen 80;
    server_name your-laravel-app.com;
    root /var/www/laravel/public; # Đường dẫn tới thư mục public của Laravel

    index index.php index.html index.htm;

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

    # Cấu hình cache
    set $cache_bypass 0;

    # Không cache các yêu cầu POST, PUT, DELETE, PATCH
    if ($request_method ~* (POST|PUT|DELETE|PATCH)) {
        set $cache_bypass 1;
    }

    # Không cache các yêu cầu có cookie liên quan đến authentication hoặc session
    if ($http_cookie ~* "laravel_session|remember_") {
        set $cache_bypass 1;
    }

    # Không cache các API endpoint nhạy cảm
    if ($request_uri ~* "^/api/user" | "^/api/settings") {
        set $cache_bypass 1;
    }

    # Không cache các trang có tham số query_string cụ thể (ví dụ: search)
    if ($query_string != "") {
        set $cache_bypass 1;
    }

    # Kích hoạt cache
    add_header X-Cache-Status $upstream_cache_status;
    proxy_cache laravel_cache;
    proxy_cache_valid 200 1h;       # Cache 1 giờ cho status 200
    proxy_cache_valid 404 1m;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
    proxy_ignore_headers Cache-Control Expires Set-Cookie;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Thay đổi theo version PHP
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param CACHE_BYPASS $cache_bypass; # Truyền biến bypass

        # Các quy tắc fastcgi khác...
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    # Cấu hình cho file tĩnh (nếu có)
    location ~* \.(css|js|jpg|jpeg|gif|png|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public";
        access_log off;
    }

    location ~ /\.ht {
        deny all;
    }
}
  • try_files $uri /index.php?$query_string;: Quy tắc quan trọng cho Laravel để định tuyến yêu cầu.
  • Các lệnh if kiểm tra các điều kiện không cache, bao gồm cả các phương thức HTTP và cookie của Laravel.
  • proxy_cache_valid 200 1h;: Thời gian cache mặc định cho các trang thành công là 1 giờ.

Bước 3: Cấu hình NGINX cho Laravel (Sử dụng NGINX Unit / Gunicorn / uWSGI)

Nếu bạn dùng các server application khác.

# /etc/nginx/sites-available/your-laravel-app.conf
server {
    listen 80;
    server_name your-laravel-app.com;

    location / {
        proxy_pass http://backend_server; # Địa chỉ backend server của bạn (ví dụ: http://127.0.0.1:8000)
        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;

        # Cấu hình cache
        set $cache_bypass 0;

        # Không cache các yêu cầu POST, PUT, DELETE, PATCH
        if ($request_method ~* (POST|PUT|DELETE|PATCH)) {
            set $cache_bypass 1;
        }
        # Không cache các yêu cầu có cookie
        if ($http_cookie ~* "laravel_session|remember_") {
            set $cache_bypass 1;
        }
        # Không cache các API endpoint nhạy cảm
        if ($request_uri ~* "^/api/user" | "^/api/settings") {
            set $cache_bypass 1;
        }
        # Không cache các trang có tham số query_string
        if ($query_string != "") {
            set $cache_bypass 1;
        }

        # Kích hoạt cache
        add_header X-Cache-Status $upstream_cache_status;
        proxy_cache laravel_cache;
        proxy_cache_valid 200 1h;
        proxy_cache_valid 404 1m;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
        proxy_ignore_headers Cache-Control Expires Set-Cookie;
    }

    # Cấu hình cho file tĩnh (nếu có)
    location ~* \.(css|js|jpg|jpeg|gif|png|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public";
        access_log off;
    }
}

# upstream block nếu bạn dùng load balancer hoặc nhiều backend server
# upstream backend_server {
#     server 127.0.0.1:8000;
#     # server 127.0.0.1:8001;
# }
  • proxy_pass http://backend_server;: Chuyển tiếp yêu cầu đến backend server.
  • Các quy tắc cache tương tự như khi dùng PHP-FPM.

💡 Mẹo: Đối với Laravel, bạn có thể tạo một middleware riêng để xử lý logic $cache_bypass dựa trên các điều kiện phức tạp hơn, thay vì chỉ dùng if trong NGINX.

Bước 4: Kiểm tra và Reload NGINX

Thực hiện kiểm tra cú pháp và reload NGINX như đã hướng dẫn cho WordPress.

sudo nginx -t
sudo systemctl reload nginx

Sử dụng công cụ developer của trình duyệt để kiểm tra header X-Cache-Status.

Tối ưu hóa NGINX caching

Tóm gọn: Điều chỉnh thời gian cache, loại bỏ header không cần thiết và sử dụng cache cho file tĩnh để tối đa hóa hiệu quả.

Điều chỉnh thời gian cache (proxy_cache_valid)

  • Nội dung tĩnh (ảnh, CSS, JS): Có thể cache rất lâu (ví dụ: 1y).
  • Nội dung động ít thay đổi: Cache lâu hơn (ví dụ: 1h1d).
  • Nội dung thay đổi thường xuyên: Cache ngắn hơn (ví dụ: 5m10m).
# Ví dụ cache lâu hơn cho các trạng thái thành công
proxy_cache_valid 200 302 60m; # Cache 60 phút
proxy_cache_valid 301 1y;      # Cache 1 năm cho redirect
proxy_cache_valid 404 1m;

Sử dụng proxy_cache_key linh hoạt

Khóa cache nên bao gồm các yếu tố phân biệt yêu cầu.

  • Chỉ URL: $scheme$request_method$host$request_uri (phổ biến).
  • Bao gồm User Agent: $scheme$request_method$host$request_uri$http_user_agent (nếu nội dung khác nhau theo thiết bị).

Cache các file tĩnh hiệu quả hơn

Mặc định NGINX đã có cấu hình cho file tĩnh, nhưng bạn có thể kết hợp với proxy cache.

location ~* \.(jpg|jpeg|gif|png|ico|svg|webp)$ {
    proxy_cache wp_cache; # Hoặc laravel_cache
    proxy_cache_valid 200 30d;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    expires 30d;
    add_header Cache-Control "public";
}

Loại bỏ các header không cần thiết

Sử dụng proxy_hide_header để ẩn các header từ backend có thể ảnh hưởng đến cache hoặc không cần thiết cho client.

proxy_hide_header X-Powered-By;
proxy_hide_header X-Frame-Options;
proxy_hide_header X-XSS-Protection;

💡 Mẹo: Sử dụng curl -I your-domain.com để xem tất cả các header được trả về và quyết định header nào cần ẩn.

Pitfalls & lỗi thường gặp

Tóm gọn: Lỗi cấu hình cache có thể dẫn đến việc hiển thị nội dung cũ hoặc không cache được.

  • Hiển thị nội dung cũ (stale content):
    • Nguyên nhân: Thời gian cache quá dài, không có cơ chế làm mới cache.
    • Cách fix: Giảm proxy_cache_valid, sử dụng proxy_cache_use_stale hợp lý, hoặc triển khai cơ chế xóa cache khi nội dung thay đổi (ví dụ: qua API hoặc hook).
  • Cache không hoạt động (luôn là MISS):
    • Nguyên nhân: Các điều kiện if trong NGINX quá nghiêm ngặt, bypass cache liên tục. Cookie, phương thức POST, hoặc tham số URL không mong muốn.
    • Cách fix: Rà soát lại các điều kiện if, proxy_cache_key, và proxy_ignore_headers. Đảm bảo NGINX có quyền ghi vào thư mục cache.
  • Lỗi 502 Bad Gateway / 504 Gateway Timeout:
    • Nguyên nhân: Backend server gặp sự cố, NGINX không thể lấy phản hồi mới.
    • Cách fix: Đảm bảo proxy_cache_use_stale được cấu hình để NGINX có thể trả về dữ liệu cache cũ thay vì báo lỗi. Kiểm tra log của backend server.
  • Cache bị ghi đè bởi header Set-Cookie:
    • Nguyên nhân: Backend gửi header Set-Cookie, NGINX mặc định sẽ không cache.
    • Cách fix: Sử dụng proxy_ignore_headers Set-Cookie; để NGINX bỏ qua header này và cache theo cấu hình của nó. Cẩn thận khi áp dụng cho toàn bộ site, có thể ảnh hưởng đến session người dùng.
  • Dung lượng cache quá lớn:
    • Nguyên nhân: max_size thiết lập quá cao hoặc không có inactive timeout hợp lý.
    • Cách fix: Điều chỉnh max_sizeinactive trong proxy_cache_path. Theo dõi dung lượng đĩa sử dụng.

⚠️ Cảnh báo: Luôn kiểm tra kỹ các quy tắc bypass cache, đặc biệt là với các trang nhạy cảm như giỏ hàng, thanh toán, hoặc trang quản trị. Sai sót có thể dẫn đến lộ thông tin hoặc lỗi nghiệp vụ nghiêm trọng.

Key takeaways

  • NGINX proxy caching là giải pháp hiệu quả để giảm tải CPU, tăng tốc độ cho WordPress và Laravel.
  • Cấu hình proxy_cache_pathproxy_cache là cốt lõi, cần xác định đúng vùng cache và thời gian hợp lệ.
  • Cần xác định rõ các yêu cầu nào không nên cache (POST, cookie admin, session) và sử dụng biến $cache_bypass để quản lý.
  • proxy_cache_keyproxy_ignore_headers là các tùy chọn quan trọng để kiểm soát chính xác quá trình caching.
  • Luôn kiểm tra header X-Cache-Status và log NGINX để gỡ lỗi khi cần.

FAQ

H3: NGINX caching có thay thế được plugin caching của WordPress/Laravel không?

Trả lời: Có, NGINX caching ở tầng web server thường hiệu quả hơn và giảm tải cho PHP/backend nhiều hơn so với plugin chạy ở tầng ứng dụng. Tuy nhiên, bạn nên tắt page cache của plugin để tránh xung đột.

H3: Làm sao để xóa cache khi cập nhật nội dung?

Trả lời: Cách đơn giản nhất là reload NGINX (sudo systemctl reload nginx), nhưng điều này sẽ xóa toàn bộ cache. Các giải pháp nâng cao bao gồm sử dụng NGINX Purge module hoặc tạo một endpoint API để xóa cache theo URL cụ thể.

H3: Cache có hoạt động với HTTPS không?

Trả lời: Có, NGINX caching hoạt động hoàn toàn bình thường với HTTPS. proxy_cache_key thường bao gồm $scheme để phân biệt HTTP và HTTPS.

H3: Tôi có nên cache toàn bộ trang web không?

Trả lời: Không nên. Các trang yêu cầu tương tác người dùng cao, có dữ liệu cá nhân hoặc thay đổi liên tục (ví dụ: giỏ hàng, trang đăng nhập, API endpoint nhạy cảm) không nên được cache hoặc chỉ cache trong thời gian rất ngắn.

H3: NGINX caching có tốn thêm tài nguyên không?

Trả lời: Có tốn thêm một ít RAM cho keys_zone và dung lượng đĩa cho cache. Tuy nhiên, mức tăng này thường rất nhỏ so với lợi ích giảm tải CPU và I/O đáng kể mà nó mang lại.

H3: Phiên bản NGINX nào hỗ trợ proxy caching?

Trả lời: Tính năng proxy caching đã có sẵn từ các phiên bản NGINX rất sớm và được cải tiến qua các phiên bản. Hầu hết các phiên bản NGINX hiện đại đều hỗ trợ đầy đủ.

Cần VPS chạy NGINX caching?

Tối ưu hóa website với NGINX caching là bước đi thông minh để cải thiện hiệu suất và tiết kiệm chi phí. Hãy bắt đầu ngay hôm nay!

Với VPS tại vsis.net, bạn có thể dễ dàng cài đặt và cấu hình NGINX để tận dụng sức mạnh của caching, đảm bảo website của bạn luôn nhanh và ổn định, ngay cả khi traffic tăng cao. Chọn ngay VPS phù hợp tại vsis.net/vps!

Lên đầu trang