Setup
Aku host WordPress aku sendiri guna Docker — NGINX + WordPress + MySQL dalam container berasingan. Baru-baru ni aku enable NGINX FastCGI Cache dan hasilnya memang nampak beza.
Apa FastCGI Cache Buat
Dia simpan versi statik HTML kat level NGINX. Bila visitor hit page yang sama, NGINX serve terus dari cache tanpa perlu go through WordPress → PHP → MySQL. Jimat resource, laju gila.
Docker Compose (simplified)
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./wordpress:/var/www/html
- nginx-cache:/var/run/nginx-cache
depends_on:
- wordpress
wordpress:
image: wordpress:php8.2-fpm
volumes:
- ./wordpress:/var/www/html
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wp
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: secret
db:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql
environment:
MYSQL_DATABASE: wp
MYSQL_USER: wp
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
db-data:
nginx-cache:
Yang penting: NGINX dan WordPress share volume /var/www/html, dan ada dedicated volume untuk cache.
NGINX Config
nginx.conf (main context)
http {
# FastCGI cache path
fastcgi_cache_path /var/run/nginx-cache levels=1:2
keys_zone=WORDPRESS:100m
inactive=60m
max_size=512m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# Cache status header — so kita boleh verify
add_header X-FastCGI-Cache $upstream_cache_status;
include /etc/nginx/conf.d/*.conf;
}
default.conf (server block)
server {
listen 80;
server_name azmi.my;
root /var/www/html;
index index.php;
# Skip cache for logged-in users and POST requests
set $skip_cache 0;
if ($request_method = POST) {
set $skip_cache 1;
}
if ($http_cookie ~* "wordpress_logged_in") {
set $skip_cache 1;
}
if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass wordpress:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Cache settings
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
}
# Browser cache for static files
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Apa Yang Berlaku
- First visit — NGINX forward ke PHP-FPM, WordPress generate page, NGINX simpan copy dalam cache
- Second visit (same page) — NGINX serve terus dari cache, PHP tak disentuh langsung
/wp-admin, logged-in users, POST requests — bypass cache (tak nak serve stale admin pages)- Static files (.css, .js, images) — browser cache 30 hari
Verify Cache Working
curl -I https://azmi.my/ # Look for this header: X-FastCGI-Cache: HIT
Possible values:
- HIT — served from cache ✅
- MISS — not in cache, generated fresh (first visit)
- BYPASS — skipped cache (logged in / POST / wp-admin)
Result
- Response time bawah 100ms untuk cached pages (sebelum ni 800ms+)
- PageSpeed score naik — especially Time to First Byte (TTFB)
- Server load turun drastik — PHP-FPM barely touched untuk normal traffic
- Boleh handle lebih banyak concurrent visitors tanpa upgrade server
Cache Purge
Bila update post, cache kena clear. Dua cara:
Manual:
# Clear semua cache rm -rf /var/run/nginx-cache/* # Atau reload nginx docker exec nginx nginx -s reload
Auto (plugin): Install “Nginx Helper” plugin dalam WordPress. Set purge on post update. Dia tulis ke file yang NGINX monitor.
Tips Tambahan
- Redis object cache — tambah Redis container + WP Redis plugin untuk cache database queries. Lagi satu layer speed.
- Cache exceptions — kalau ada WooCommerce atau dynamic pages, add more skip rules
- Monitor cache hit ratio — check access log, grep for HIT/MISS/BYPASS. Kalau banyak MISS, something wrong.
- Disk space —
max_size=512mcukup untuk most blogs. Monitor/var/run/nginx-cachesize.
Kombinasi NGINX FastCGI Cache + Docker + WordPress — prestasi tinggi, takde kos tambahan, takde plugin berat. Kalau korang self-host WordPress, try la.