Bài 6: NGINX CACHING
Bài học về Caching trong Nginx - browser caching với expires và Cache-Control headers, proxy caching, FastCGI caching cho PHP, cache keys và zones. Hướng dẫn cache purging, bypass strategies và optimization techniques. Bao gồm examples thực tế để tăng performance và giảm load.
TAGS
#Nginx #Caching #ProxyCache #FastCGI #BrowserCache #CacheControl #Expires #Performance #Optimization #CDN #CachePurging #CacheBypass #WebPerformance #StaticContent #DynamicContent #Tutorial #Production #BestPractices #DevOps #Infrastructure
1. Browser Caching với Expires và Cache-Control Headers
Browser caching lưu trữ files tại client browser, giảm số requests đến server và tăng tốc độ load.
1.1. Expires Header
Expires header chỉ định thời điểm cụ thể khi cache hết hạn.
Cú pháp cơ bản:
location ~* \.(jpg|jpeg|png|gif|ico)$ {
expires 30d; # Cache 30 ngày
}
Các giá trị expires:
server {
listen 80;
server_name example.com;
root /var/www/html;
# Images - cache lâu
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 1y; # 1 năm
add_header Cache-Control "public, immutable";
}
# CSS và JavaScript - cache trung bình
location ~* \.(css|js)$ {
expires 1M; # 1 tháng
add_header Cache-Control "public";
}
# HTML - cache ngắn hoặc no-cache
location ~* \.html$ {
expires 1h; # 1 giờ
add_header Cache-Control "public, must-revalidate";
}
# API responses - không cache
location /api/ {
expires -1; # Không cache
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
Time units:
expires 1s; # 1 second
expires 5m; # 5 minutes
expires 2h; # 2 hours
expires 7d; # 7 days
expires 3M; # 3 months (30 days)
expires 1y; # 1 year
expires -1; # Không cache (Cache-Control: no-cache)
expires epoch; # Expires: Thu, 01 Jan 1970 00:00:01 GMT
expires max; # Expires: Thu, 31 Dec 2037 23:55:55 GMT
expires off; # Không set Expires header
Ví dụ chi tiết:
server {
listen 80;
server_name cdn.example.com;
root /var/www/cdn;
# Versioned assets - cache vĩnh viễn
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf)$ {
# Chỉ áp dụng cho files có version trong tên
# vd: style.v1.2.3.css, app.20240101.js
if ($uri ~ "\.v[0-9]+\.|\.v?\d{8,}\.") {
expires max;
add_header Cache-Control "public, immutable";
}
# Files không có version
expires 1M;
add_header Cache-Control "public";
}
# Videos - cache lâu nhưng có thể revalidate
location ~* \.(mp4|webm|ogg|avi)$ {
expires 6M;
add_header Cache-Control "public, max-age=15552000";
}
# Documents - cache ngắn
location ~* \.(pdf|doc|docx|xls|xlsx)$ {
expires 1d;
add_header Cache-Control "public, max-age=86400";
}
}
1.2. Cache-Control Header
Cache-Control là modern alternative cho Expires, flexible hơn.
Cache-Control directives:
# public: Có thể cache bởi browser và intermediate caches
add_header Cache-Control "public";
# private: Chỉ browser cache, không cache ở proxies
add_header Cache-Control "private";
# no-cache: Phải revalidate trước khi dùng cache
add_header Cache-Control "no-cache";
# no-store: Không cache gì cả
add_header Cache-Control "no-store";
# max-age: Cache duration (seconds)
add_header Cache-Control "public, max-age=31536000";
# s-maxage: Max-age cho shared caches (CDN, proxies)
add_header Cache-Control "public, max-age=3600, s-maxage=86400";
# must-revalidate: Phải revalidate khi stale
add_header Cache-Control "public, max-age=3600, must-revalidate";
# immutable: Content không bao giờ thay đổi
add_header Cache-Control "public, max-age=31536000, immutable";
# no-transform: Không cho phép transform content
add_header Cache-Control "public, no-transform";
Combining directives:
server {
listen 80;
server_name example.com;
# Static assets với versioning - immutable
location ~* /static/.*\.(css|js)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Images - public, long cache
location ~* \.(jpg|png|gif|svg)$ {
expires 6M;
add_header Cache-Control "public, max-age=15552000";
}
# HTML - cache ngắn với revalidation
location ~* \.html$ {
expires 10m;
add_header Cache-Control "public, max-age=600, must-revalidate";
}
# User-specific content - private
location /dashboard/ {
add_header Cache-Control "private, max-age=300";
}
# Sensitive data - no cache
location /account/ {
add_header Cache-Control "private, no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
}
1.3. Conditional Caching
map $sent_http_content_type $expires {
default off;
text/html 1h;
text/css 1M;
application/javascript 1M;
~image/ 1y;
application/pdf 7d;
~font/ 1y;
}
server {
listen 80;
server_name example.com;
expires $expires;
# Override cho specific paths
location /news/ {
expires 5m;
add_header Cache-Control "public, max-age=300";
}
}
Cache dựa trên file extension:
server {
listen 80;
root /var/www/html;
# Map file extensions to cache duration
location / {
if ($request_uri ~* "\.(jpg|jpeg|png|gif|ico)$") {
expires 1y;
add_header Cache-Control "public, immutable";
}
if ($request_uri ~* "\.(css|js)$") {
expires 1M;
add_header Cache-Control "public";
}
if ($request_uri ~* "\.html$") {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
try_files $uri $uri/ =404;
}
}
1.4. ETag và Last-Modified
server {
listen 80;
server_name example.com;
# Enable ETag
etag on;
# Enable Last-Modified header
if_modified_since before;
location / {
root /var/www/html;
# Browser sẽ gửi If-None-Match (ETag) hoặc If-Modified-Since
# Nginx trả về 304 Not Modified nếu file không thay đổi
}
}
Example với conditional requests:
server {
listen 80;
server_name api.example.com;
location /api/data {
proxy_pass http://backend;
# Pass conditional headers to backend
proxy_set_header If-Modified-Since $http_if_modified_since;
proxy_set_header If-None-Match $http_if_none_match;
# Backend returns 304 if not modified
# Nginx forwards 304 to client
}
}
2. Proxy Caching Cơ bản
Proxy caching lưu trữ responses từ backend servers, giảm load và response time.
2.1. Cấu hình Proxy Cache Zone
# Define cache path và settings (trong http context)
http {
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=my_cache:10m
max_size=1g
inactive=60m
use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# Enable caching
proxy_cache my_cache;
# Cache durations
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 5m;
# Add cache status header
add_header X-Cache-Status $upstream_cache_status;
}
}
}
Giải thích parameters:
proxy_cache_path /var/cache/nginx/proxy # Đường dẫn lưu cache
levels=1:2 # Cấu trúc thư mục (tối ưu I/O)
keys_zone=my_cache:10m # Tên zone và size của shared memory
max_size=1g # Max cache size trên disk
inactive=60m # Xóa cache không dùng sau 60 phút
use_temp_path=off; # Ghi trực tiếp vào cache path
Levels explained:
levels=1:2 tạo structure:
/var/cache/nginx/proxy/
├── a/
│ ├── 3c/
│ │ └── abc123...def
│ └── 7f/
└── b/
└── 2d/
First level: 1 character (a, b, c...)
Second level: 2 characters (3c, 7f, 2d...)
2.2. Cache Status Values
$upstream_cache_status có thể là:
- MISS : Request không có trong cache, fetched từ backend
- HIT : Request served từ cache
- EXPIRED : Cache entry expired, fetched từ backend
- STALE : Serving stale content (nếu configured)
- UPDATING : Cache đang update từ backend
- REVALIDATED: Cache revalidated với backend (304)
- BYPASS : Cache bị bypass (theo config)
Logging cache status:
http {
log_format cache_log '$remote_addr - [$time_local] '
'"$request" $status '
'Cache: $upstream_cache_status '
'Time: $upstream_response_time';
server {
listen 80;
access_log /var/log/nginx/cache.log cache_log;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
add_header X-Cache-Status $upstream_cache_status always;
}
}
}
2.3. Cache Key
Cache key xác định uniqueness của cached items.
Default cache key:
proxy_cache_key $scheme$proxy_host$request_uri;
# Example:
# http://example.com/page?id=1
# Key: httpexample.com/page?id=1
Custom cache keys:
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Include request method
proxy_cache_key "$scheme$request_method$host$request_uri";
# Include specific headers
# proxy_cache_key "$scheme$host$request_uri$http_accept_language";
# Include cookies
# proxy_cache_key "$scheme$host$request_uri$cookie_session";
}
Example với user-specific caching:
map $cookie_user_id $cache_user {
default $cookie_user_id;
"" "anonymous";
}
server {
location /api/ {
proxy_pass http://backend;
proxy_cache user_cache;
# Different cache per user
proxy_cache_key "$scheme$host$request_uri$cache_user";
}
}
2.4. Cache Methods và Conditions
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Chỉ cache GET và HEAD methods
proxy_cache_methods GET HEAD;
# Cache durations dựa trên status code
proxy_cache_valid 200 301 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 5m;
# Minimum số requests trước khi cache
proxy_cache_min_uses 3;
# Cache kể cả khi backend error
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# Lock để tránh cache stampede
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_cache_lock_age 5s;
}
}
proxy_cache_use_stale explained:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# Serve stale cache khi:
# - error: Lỗi kết nối đến backend
# - timeout: Backend timeout
# - updating: Cache đang được update (tránh stampede)
# - http_500/502/503/504: Backend trả về error codes
2.5. Complete Proxy Cache Example
http {
# Define multiple cache zones
proxy_cache_path /var/cache/nginx/static
levels=1:2
keys_zone=static_cache:10m
max_size=500m
inactive=60m
use_temp_path=off;
proxy_cache_path /var/cache/nginx/api
levels=1:2
keys_zone=api_cache:10m
max_size=200m
inactive=10m
use_temp_path=off;
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8080;
}
server {
listen 80;
server_name example.com;
# Static content cache
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
proxy_pass http://backend;
proxy_cache static_cache;
proxy_cache_valid 200 30d;
proxy_cache_valid 404 1h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
expires 30d;
add_header Cache-Control "public, immutable";
add_header X-Cache-Status $upstream_cache_status;
}
# API cache
location /api/ {
proxy_pass http://backend;
proxy_cache api_cache;
proxy_cache_valid 200 5m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri$http_authorization";
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 2;
proxy_cache_use_stale error timeout updating;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
}
# No cache for user-specific content
location /account/ {
proxy_pass http://backend;
proxy_cache off;
proxy_no_cache 1;
proxy_cache_bypass 1;
}
}
}
3. FastCGI Caching
FastCGI caching dùng cho dynamic content như PHP applications.
3.1. FastCGI Cache Configuration
http {
# Define FastCGI cache zone
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=php_cache:10m
max_size=500m
inactive=60m
use_temp_path=off;
# Cache key
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Enable FastCGI cache
fastcgi_cache php_cache;
# Cache valid durations
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 10m;
# Cache use stale
fastcgi_cache_use_stale error timeout updating invalid_header http_500;
# Cache locking
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s;
# Minimum uses before caching
fastcgi_cache_min_uses 2;
# Add cache status header
add_header X-FastCGI-Cache $upstream_cache_status;
}
}
}
3.2. WordPress với FastCGI Cache
http {
fastcgi_cache_path /var/cache/nginx/wordpress
levels=1:2
keys_zone=wordpress:100m
max_size=1g
inactive=60m
use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
listen 80;
server_name blog.example.com;
root /var/www/wordpress;
index index.php;
# Set cache bypass conditions
set $skip_cache 0;
# POST requests và URLs với query strings
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache URIs containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't cache logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# FastCGI cache settings
fastcgi_cache wordpress;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 10m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
fastcgi_cache_lock on;
# Headers
add_header X-FastCGI-Cache $upstream_cache_status;
add_header Cache-Control "public, max-age=3600";
}
# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# Deny access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
}
3.3. Drupal với FastCGI Cache
http {
fastcgi_cache_path /var/cache/nginx/drupal
levels=1:2
keys_zone=drupal:100m
max_size=2g
inactive=60m
use_temp_path=off;
server {
listen 80;
server_name drupal.example.com;
root /var/www/drupal;
# Cache bypass conditions
set $skip_cache 0;
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
if ($request_uri ~* "^/(admin|user|cart|checkout)/") {
set $skip_cache 1;
}
if ($http_cookie ~* "SESS") {
set $skip_cache 1;
}
location / {
try_files $uri /index.php?$query_string;
}
location ~ '\.php$|^/update.php' {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache drupal;
fastcgi_cache_valid 200 301 302 5m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout updating invalid_header http_500;
fastcgi_cache_lock on;
add_header X-FastCGI-Cache $upstream_cache_status;
}
location ~ ^/sites/.*/files/styles/ {
try_files $uri @rewrite;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
}
3.4. Custom PHP Application với Cache
http {
fastcgi_cache_path /var/cache/nginx/app
levels=1:2
keys_zone=app_cache:50m
max_size=1g
inactive=30m
use_temp_path=off;
# Custom cache key with user context
map $http_cookie $user_context {
default "anonymous";
~*user_id=(?<uid>[^;]+) $uid;
}
server {
listen 80;
server_name app.example.com;
root /var/www/app/public;
# Cache bypass cho authenticated users
set $skip_cache 0;
if ($http_cookie ~* "logged_in") {
set $skip_cache 1;
}
if ($request_uri ~* "/(api|admin)/") {
set $skip_cache 1;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Custom cache key
fastcgi_cache_key "$scheme$request_method$host$request_uri$user_context";
fastcgi_cache app_cache;
fastcgi_cache_valid 200 10m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout updating;
fastcgi_cache_lock on;
fastcgi_cache_min_uses 3;
# Custom headers
add_header X-Cache-Status $upstream_cache_status;
add_header X-Cache-Key "$scheme$request_method$host$request_uri$user_context";
}
}
}
4. Cache Keys và Cache Zones
4.1. Cache Zones Configuration
http {
# Static content cache - large, long-lived
proxy_cache_path /var/cache/nginx/static
levels=1:2
keys_zone=static:100m
max_size=5g
inactive=7d
use_temp_path=off;
# API cache - smaller, short-lived
proxy_cache_path /var/cache/nginx/api
levels=1:2
keys_zone=api:50m
max_size=1g
inactive=1h
use_temp_path=off;
# User-specific cache
proxy_cache_path /var/cache/nginx/user
levels=1:2
keys_zone=user:50m
max_size=2g
inactive=30m
use_temp_path=off;
# HTML pages cache
proxy_cache_path /var/cache/nginx/pages
levels=1:2
keys_zone=pages:20m
max_size=500m
inactive=2h
use_temp_path=off;
}
Zone size calculation:
keys_zone size stores cache metadata:
- 1MB ≈ 8000 keys
- 10MB ≈ 80,000 keys
- 100MB ≈ 800,000 keys
Max cache size stores actual content:
- Set based on available disk space
- Monitor /var/cache/nginx disk usage
4.2. Advanced Cache Keys
Cache by device type:
map $http_user_agent $device {
default desktop;
~*mobile mobile;
~*tablet tablet;
}
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Different cache per device
proxy_cache_key "$scheme$host$request_uri$device";
add_header X-Device $device;
add_header X-Cache-Status $upstream_cache_status;
}
}
Cache by accept headers:
map $http_accept $content_type_key {
default "html";
~*application/json "json";
~*application/xml "xml";
}
server {
location /api/ {
proxy_pass http://backend;
proxy_cache api_cache;
# Different cache per content type
proxy_cache_key "$scheme$host$request_uri$content_type_key";
}
}
Cache by language:
map $http_accept_language $lang {
default en;
~*^vi vi;
~*^ja ja;
~*^zh zh;
}
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Different cache per language
proxy_cache_key "$scheme$host$request_uri$lang";
add_header Content-Language $lang;
}
}
Cache by geo location:
geo $country {
default US;
192.168.1.0/24 VN;
10.0.0.0/8 JP;
}
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Different cache per country
proxy_cache_key "$scheme$host$request_uri$country";
}
}
Complex cache key:
map $http_cookie $user_segment {
default "guest";
~*premium=1 "premium";
~*vip=1 "vip";
}
server {
location /api/ {
proxy_pass http://backend;
proxy_cache api_cache;
# Cache key combining multiple factors
proxy_cache_key "$scheme$host$request_uri$user_segment$device$lang";
add_header X-Cache-Key-Components "segment:$user_segment|device:$device|lang:$lang";
}
}
4.3. Cache Hierarchy
http {
# L1 Cache - Memory (small, fast)
proxy_cache_path /dev/shm/nginx
levels=1
keys_zone=l1_cache:10m
max_size=100m
inactive=5m
use_temp_path=off;
# L2 Cache - SSD (medium, fast)
proxy_cache_path /var/cache/nginx/l2
levels=1:2
keys_zone=l2_cache:50m
max_size=5g
inactive=1h
use_temp_path=off;
# L3 Cache - HDD (large, slower)
proxy_cache_path /mnt/cache/nginx/l3
levels=1:2
keys_zone=l3_cache:100m
max_size=50g
inactive=7d
use_temp_path=off;
server {
location /api/hot/ {
# Frequently accessed - L1 cache
proxy_pass http://backend;
proxy_cache l1_cache;
proxy_cache_valid 200 5m;
}
location /api/warm/ {
# Moderately accessed - L2 cache
proxy_pass http://backend;
proxy_cache l2_cache;
proxy_cache_valid 200 1h;
}
location /api/cold/ {
# Rarely accessed - L3 cache
proxy_pass http://backend;
proxy_cache l3_cache;
proxy_cache_valid 200 1d;
}
}
}
5. Cache Purging và Bypass
5.1. Cache Bypass
server {
listen 80;
# Bypass cache với special header
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Bypass if X-No-Cache header present
proxy_cache_bypass $http_x_no_cache;
# Or bypass with cookie
proxy_cache_bypass $cookie_nocache;
# Or bypass with argument
proxy_cache_bypass $arg_nocache;
}
}
Multiple bypass conditions:
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Set bypass conditions
set $cache_bypass 0;
# Bypass for specific cookies
if ($http_cookie ~* "admin_logged_in") {
set $cache_bypass 1;
}
# Bypass for specific URLs
if ($request_uri ~* "^/(admin|dashboard)/") {
set $cache_bypass 1;
}
# Bypass for POST requests
if ($request_method = POST) {
set $cache_bypass 1;
}
# Apply bypass
proxy_cache_bypass $cache_bypass;
proxy_no_cache $cache_bypass;
}
}
Bypass với query parameter:
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# ?nocache=1 → bypass cache
proxy_cache_bypass $arg_nocache;
# ?refresh=1 → refresh cache
proxy_cache_bypass $arg_refresh;
add_header X-Cache-Bypass $arg_nocache;
}
}
# Usage:
# Normal: http://example.com/page
# Bypass: http://example.com/page?nocache=1
# Refresh: http://example.com/page?refresh=1
5.2. Cache Purging (Nginx Plus / Third-party module)
Nginx Plus purge:
# Nginx Plus only
map $request_method $purge_method {
PURGE 1;
default 0;
}
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_purge $purge_method;
}
}
# Usage:
# curl -X PURGE http://example.com/page
Cache purge với open source module:
# Install ngx_cache_purge module
# Ubuntu/Debian
sudo apt install libnginx-mod-http-cache-purge
# CentOS - compile from source
http {
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=my_cache:10m;
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_key "$scheme$host$request_uri";
}
# Purge location
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
proxy_cache_purge my_cache "$scheme$host$1";
}
}
}
# Usage:
# curl http://example.com/purge/page-to-clear
Manual cache purging:
#!/bin/bash
# purge_cache.sh - Manual cache purge script
CACHE_DIR="/var/cache/nginx"
CACHE_ZONE="my_cache"
# Purge all cache
purge_all() {
echo "Purging all cache..."
sudo rm -rf ${CACHE_DIR}/${CACHE_ZONE}/*
echo "Cache purged!"
}
# Purge specific URL
purge_url() {
local url=$1
local cache_key=$(echo -n "$url" | md5sum | awk '{print $1}')
local cache_path=$(find ${CACHE_DIR}/${CACHE_ZONE} -name "*${cache_key}*")
if [ -n "$cache_path" ]; then
echo "Purging cache for: $url"
sudo rm -f $cache_path
echo "Purged: $cache_path"
else
echo "No cache found for: $url"
fi
}
# Purge by pattern
purge_pattern() {
local pattern=$1
echo "Purging cache matching: $pattern"
sudo find ${CACHE_DIR}/${CACHE_ZONE} -type f -name "*${pattern}*" -delete
echo "Done!"
}
case "$1" in
all)
purge_all
;;
url)
purge_url "$2"
;;
pattern)
purge_pattern "$2"
;;
*)
echo "Usage: $0 {all|url <url>|pattern <pattern>}"
exit 1
;;
esac
Cache warmup script:
#!/bin/bash
# cache_warmup.sh - Warm up cache
URLS=(
"http://example.com/"
"http://example.com/products"
"http://example.com/about"
"http://example.com/contact"
)
echo "Starting cache warmup..."
for url in "${URLS[@]}"; do
echo "Warming up: $url"
curl -s -o /dev/null -w "Status: %{http_code}, Time: %{time_total}s\n" "$url"
sleep 0.5
done
echo "Cache warmup complete!"
5.3. Selective Cache Invalidation
# API để invalidate cache
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 10m;
}
# Cache invalidation endpoint
location /api/cache/invalidate {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
content_by_lua_block {
local pattern = ngx.var.arg_pattern
if pattern then
-- Invalidate cache matching pattern
-- Implementation depends on cache module
ngx.say("Cache invalidated for pattern: ", pattern)
else
ngx.say("Pattern required")
end
}
}
}
# Usage:
# curl "http://example.com/api/cache/invalidate?pattern=/products/*"
6. Bài tập Thực hành
Bài tập 1: Browser Caching
- Setup static file server
- Configure expires headers:
- Images: 1 year
- CSS/JS: 1 month
- HTML: 1 hour
- Test với browser DevTools (Network tab)
- Verify cache headers
Bài tập 2: Proxy Cache
- Setup backend server (Node.js/Python)
- Configure Nginx proxy cache
- Generate traffic và monitor cache hits/misses
- Check cache files in
/var/cache/nginx
Bài tập 3: FastCGI Cache cho WordPress
- Install WordPress
- Configure FastCGI cache
- Test cache bypass cho:
- Logged-in users
- Admin pages
- POST requests
- Measure performance improvement
Bài tập 4: Custom Cache Keys
- Setup cache với custom key (include device type)
- Test từ mobile và desktop
- Verify different cached versions
Bài tập 5: Cache Purging
- Setup proxy cache
- Create purge endpoint
- Test cache purge:
- Manual purge script
- API endpoint
- Verify cache cleared
Bài tập 6: Cache Performance Testing
- Setup với và không có cache
- Use Apache Bench để benchmark:
# Without cache
ab -n 1000 -c 10 http://example.com/
# With cache
ab -n 1000 -c 10 http://example.com/
- Compare results
7. Troubleshooting
7.1. Cache Not Working
Problem: X-Cache-Status always shows MISS
Diagnosis:
# Check cache directory permissions
ls -la /var/cache/nginx/
# Check cache config
sudo nginx -T | grep cache
# Check if cache zone defined
sudo nginx -T | grep keys_zone
# Monitor cache files being created
watch -n 1 'ls -lh /var/cache/nginx/proxy/'
Solutions:
# Ensure proper permissions
sudo chown -R nginx:nginx /var/cache/nginx/
sudo chmod -R 755 /var/cache/nginx/
# Verify cache zone
http {
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=my_cache:10m;
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache; # Must match keys_zone name
proxy_cache_valid 200 10m;
}
}
}
7.2. Cache Taking Too Much Disk Space
Problem: /var/cache/nginx fills up disk
Diagnosis:
# Check cache size
du -sh /var/cache/nginx/*
# Find largest cache files
find /var/cache/nginx -type f -exec du -h {} + | sort -rh | head -20
Solutions:
# Set max_size
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=my_cache:10m
max_size=1g # Limit to 1GB
inactive=60m; # Purge inactive files
# Or use tmpfs (RAM disk)
# Add to /etc/fstab:
# tmpfs /var/cache/nginx tmpfs defaults,size=512M 0 0
7.3. Stale Content Being Served
Problem: Old content được serve dù đã update
Solutions:
# Clear cache manually
sudo rm -rf /var/cache/nginx/proxy/*
sudo systemctl reload nginx
# Or implement cache versioning
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Add version to cache key
proxy_cache_key "$scheme$host$request_uri$arg_v";
}
# Usage: http://example.com/page?v=2
7.4. Cache Stampede
Problem: Nhiều requests cùng lúc khi cache expires
Solutions:
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Enable cache locking
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_cache_lock_age 5s;
# Use stale while updating
proxy_cache_use_stale updating;
}
7.5. Different Content for Same URL
Problem: User A sees User B's content
Solutions:
# Include user identifier in cache key
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Different cache per user
proxy_cache_key "$scheme$host$request_uri$cookie_user_id";
# Or bypass cache for authenticated users
set $skip_cache 0;
if ($http_cookie ~* "logged_in") {
set $skip_cache 1;
}
proxy_cache_bypass $skip_cache;
}
8. Best Practices
8.1. Cache Strategy
# Tiered caching strategy
http {
# Hot content - short TTL, small size
proxy_cache_path /dev/shm/nginx/hot
keys_zone=hot:10m
max_size=100m
inactive=5m;
# Warm content - medium TTL, medium size
proxy_cache_path /var/cache/nginx/warm
keys_zone=warm:50m
max_size=5g
inactive=1h;
# Cold content - long TTL, large size
proxy_cache_path /mnt/cache/nginx/cold
keys_zone=cold:100m
max_size=50g
inactive=7d;
server {
# Frequently changing content
location /api/live/ {
proxy_cache hot;
proxy_cache_valid 1m;
}
# Normal content
location / {
proxy_cache warm;
proxy_cache_valid 10m;
}
# Static assets
location /static/ {
proxy_cache cold;
proxy_cache_valid 1y;
}
}
}
8.2. Monitoring
# Detailed cache logging
log_format cache_detail '$remote_addr - [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'cache:$upstream_cache_status '
'rt:$request_time '
'urt:$upstream_response_time '
'cache_key:"$scheme$host$request_uri"';
server {
access_log /var/log/nginx/cache.log cache_detail;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
add_header X-Cache-Status $upstream_cache_status always;
add_header X-Cache-Date $upstream_http_date;
}
}
Cache statistics script:
#!/bin/bash
# cache_stats.sh
LOG_FILE="/var/log/nginx/cache.log"
echo "Cache Statistics"
echo "================"
echo "Total requests: $(wc -l < $LOG_FILE)"
echo -e "\nCache status distribution:"
awk '{print $NF}' $LOG_FILE | grep "cache:" | cut -d: -f2 | sort | uniq -c | sort -rn
echo -e "\nHit rate:"
TOTAL=$(grep "cache:" $LOG_FILE | wc -l)
HITS=$(grep "cache:HIT" $LOG_FILE | wc -l)
MISS=$(grep "cache:MISS" $LOG_FILE | wc -l)
if [ $TOTAL -gt 0 ]; then
HIT_RATE=$(echo "scale=2; ($HITS * 100) / $TOTAL" | bc)
echo "Hit rate: ${HIT_RATE}%"
echo "Hits: $HITS"
echo "Misses: $MISS"
fi
8.3. Security
# Prevent cache poisoning
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# Không cache responses với Set-Cookie
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
# Normalize cache key (remove tracking params)
if ($args ~* ^(.*)&?(utm_[^&]+)(.*)$) {
set $args $1$3;
}
proxy_cache_key "$scheme$host$request_uri$args";
}
}
8.4. Performance
# Optimize cache performance
http {
proxy_cache_path /var/cache/nginx
levels=1:2 # Distribute files
keys_zone=cache:100m
max_size=10g
inactive=60m
use_temp_path=off # Write directly to cache
loader_threshold=300 # Load cache metadata gradually
loader_files=200
loader_sleeps=50ms;
server {
location / {
proxy_pass http://backend;
proxy_cache cache;
# Buffer settings
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 16 16k;
# Cache locking
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# Background update
proxy_cache_background_update on;
proxy_cache_use_stale updating;
}
}
}
Tổng kết
Trong bài này, bạn đã học:
- ✅ Browser caching với expires và Cache-Control headers
- ✅ Proxy caching cho static và dynamic content
- ✅ FastCGI caching cho PHP applications
- ✅ Cache keys, zones và custom strategies
- ✅ Cache purging và bypass techniques
- ✅ Performance optimization và best practices
Bài tiếp theo: Chúng ta sẽ tìm hiểu về SSL/TLS và HTTPS - cách setup SSL certificates, HTTP to HTTPS redirect, SSL protocols, HSTS và HTTP/2 configuration.