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 moduleUbuntu/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/bashpurge_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/bashcache_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 filesOr 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 nginxOr 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/bashcache_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.