Nginx fastcgi_cache for WordPress Acceleration
This tutorial explains how to configure Nginx's fastcgi_cache to accelerate HTML pseudo-static page delivery for WordPress sites, based on an LNMP environment.
Prerequisites
Ensure you have an LNMP stack (e.g., LNMP 1.4 or later) with at least:
- MySQL 5.5.56
- PHP 5.5.38
- TCmalloc
Install the ngx_cache_purge Module
First, check if the module is installed:
nginx -V 2>&1 | grep -o ngx_cache_purge
If no output, install it:
- Navigate to the source directory:
cd /usr/local/src - Download ngx_cache_purge:
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz - Extract it:
tar zxvf ngx_cache_purge-2.3.tar.gz - Download matching Nginx source (e.g., 1.12.0):
wget http://nginx.org/download/nginx-1.12.0.tar.gz - Extract and enter:
tar zxvf nginx-1.12.0.tar.gz cd nginx-1.12.0 - Get current Nginx compile options:
nginx -V - Reconfigure with the module added:
./configure [your existing options] --add-module=../ngx_cache_purge-2.3 - Compile:
make - Backup and replace the binary:
mv /usr/local/nginx/sbin/nginx{,_$(date +%F)} cp objs/nginx /usr/local/nginx/sbin - Verify installation:
nginx -V 2>&1 | grep -o ngx_cache_purge
Configure fastcgi_cache
Edit your site's Nginx configuration file (e.g., /usr/local/nginx/conf/vhost/www.example.com.conf). Before the server block, add:
fastcgi_cache_path /tmp/wpcache levels=1:2 keys_zone=WORDPRESS:250m inactive=1d max_size=1G;
fastcgi_temp_path /tmp/wpcache/temp;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
Inside the server block, update the PHP location block and add cache logic:
server {
listen 80;
server_name www.example.com;
root /home/wwwroot/www.example.com;
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml|purge=all") { set $skip_cache 1; }
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $skip_cache 1; }
location ~ [^/].php(/|$) {
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
include fastcgi.conf;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache "$upstream_cache_status From $host";
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 301 302 1d;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ /purge(/.*) {
allow 127.0.0.1;
allow YOUR_SERVER_IP;
deny all;
fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
}
location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
expires max;
access_log off;
log_not_found off;
}
}
server {
server_name example.com;
return 301 $scheme://www.example.com$request_uri;
}
Save and restart Nginx: lnmp restart.
WordPress Configuration
Install the Nginx Helper plugin. In wp-config.php, add:
define('RT_WP_NGINX_HELPER_CACHE_PATH', '/tmp/wpcache');
In the plugin settings, set "Purge Method" to "Delete local server cache files".
Alternative: Code-Based Cache Purging
Add this to your theme's functions.php for automatic cache purging without a plugin:
// Configuration
$logSwitch = 0;
$logFile = '/tmp/purge.log';
$cache_path = '/tmp/wpcache';
// Manual purge for admins: ?purge=all
if (isset($_GET['purge']) && $_GET['purge'] == 'all' && is_user_logged_in() && current_user_can('manage_options')) {
delDirAndFile($cache_path, 0);
}
// Hook into publishing and comments
add_action('publish_post', 'Clean_By_Publish', 99);
add_action('comment_post', 'Clean_By_Comments', 99);
add_action('comment_unapproved_to_approved', 'Clean_By_Approved', 99);
function Clean_By_Publish($post_ID) {
$url = get_permalink($post_ID);
cleanFastCGIcache($url);
cleanFastCGIcache(home_url() . '/');
// Optional: clean category and tag pages
if ($categories = wp_get_post_categories($post_ID)) {
foreach ($categories as $cat_id) cleanFastCGIcache(get_category_link($cat_id));
}
if ($tags = get_the_tags($post_ID)) {
foreach ($tags as $tag) cleanFastCGIcache(get_tag_link($tag->term_id));
}
}
function Clean_By_Comments($comment_id) {
$comment = get_comment($comment_id);
cleanFastCGIcache(get_permalink($comment->comment_post_ID));
}
function Clean_By_Approved($comment) {
cleanFastCGIcache(get_permalink($comment->comment_post_ID));
}
function cleanFastCGIcache($url) {
global $cache_path;
$url_data = parse_url($url);
if (!$url_data) return;
$hash = md5($url_data['scheme'] . 'GET' . $url_data['host'] . $url_data['path']);
$cache_path = rtrim($cache_path, '/') . '/';
$cached_file = $cache_path . substr($hash, -1) . '/' . substr($hash, -3, 2) . '/' . $hash;
if (file_exists($cached_file)) unlink($cached_file);
}
function delDirAndFile($path, $delDir = FALSE) {
$handle = opendir($path);
if ($handle) {
while (false !== ($item = readdir($handle))) {
if ($item != "." && $item != "..") {
is_dir("$path/$item") ? delDirAndFile("$path/$item", $delDir) : unlink("$path/$item");
}
}
closedir($handle);
if ($delDir) return rmdir($path);
} else {
if (file_exists($path)) return unlink($path);
}
}
Note: Ensure purge=all is in your Nginx skip-cache rules to prevent the purge URL itself from being cached.
Additional Performance Tips
- Memcached: Use for object caching. Install via
./addons.sh install memcachedand place the appropriateobject-cache.phpinwp-content. - OPcache: Accelerates PHP execution. Enable via
./addons.sh install opcacheif not already active.
After configuration, check the X-Cache header in your browser's developer tools. A value of HIT indicates the cache is working.