1. Disabling Post Revisions
WordPress automatically saves multiple revisions of your posts and pages. While useful for tracking
changes, excessive revisions can bloat your database and slow down your site. Disabling post
revisions can improve database performance.
Implementation Steps
Navigate to WordPress directory
cd /var/www/example.com/
Edit wp-config.php
sudo nano public_html/wp-config.php
Add the following line to disable post revisions:
Configuration directive
define('WP_POST_REVISIONS', 'false');
Restart PHP-FPM service
sudo systemctl restart php8.3-fpm
Result: Post revisions are now disabled, reducing database overhead and improving
performance.
2. Configuring Memory Limits
Properly configuring memory limits is crucial for WordPress performance. PHP and WordPress both have
memory limits that should be optimized based on your site's requirements.
PHP-FPM Pool Configuration
Navigate to PHP-FPM pool directory
cd /etc/php/8.3/fpm/pool.d/
List pool configurations
ls
Edit pool configuration
sudo nano example.com.conf
Update the memory limit (comment out the 32M line and uncomment/set 256M):
Pool memory configuration
;php_admin_value[memory_limit] = 32M
php_admin_value[memory_limit] = 256M
WordPress Memory Configuration
Edit wp-config.php
sudo nano /var/www/example.com/public_html/wp-config.php
Add the WordPress memory limit directive:
WordPress memory limit
/** MEMORY LIMIT */
define('WP_MEMORY_LIMIT', '256M');
Restart PHP-FPM
sudo systemctl restart php8.3-fpm
Note: 256M is recommended for most WordPress installations. Adjust based on your
site's specific needs and available server resources.
4. Configuring OPcache
OPcache improves PHP performance by storing precompiled script bytecode in shared memory, eliminating
the need for PHP to load and parse scripts on each request.
Calculate max_accelerated_files
Navigate to web root
cd /var/www/
Count PHP files
sudo find . -type f -print | grep php | wc -l
Development Server Configuration
Navigate to pool directory
cd /etc/php/8.3/fpm/pool.d/
Edit pool configuration
sudo nano example.com.conf
Add the following OPcache configuration for development:
OPcache - Development Server (July 2025)
; Directive php_admin_flag[opcache.enabled] leave commented - enabled by
default
; php_admin_flag[opcache.enabled] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.interned_strings_buffer] = 32
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_flag[opcache.validate_timestamps] = 1
php_admin_value[opcache.revalidate_freq] = 2
php_admin_flag[opcache.validate_permission] = 1
Production Server Configuration
OPcache - Production Server (July 2025)
; Directive php_admin_flag[opcache.enabled] leave commented - enabled by
default
;php_admin_flag[opcache.enabled] = 1
;php_admin_value[opcache.memory_consumption] = 256
;php_admin_value[opcache.interned_strings_buffer] = 32
;php_admin_value[opcache.max_accelerated_files] = 20000
;php_admin_value[opcache.validate_timestamps] = 0
;php_admin_flag[opcache.validate_permission] = 1
Reload PHP-FPM
sudo systemctl reload php8.3-fpm
| Directive |
Development |
Production |
Description |
| memory_consumption |
256 MB |
256 MB |
Memory allocated for OPcache |
| interned_strings_buffer |
32 MB |
32 MB |
Memory for interned strings |
| max_accelerated_files |
20000 |
20000 |
Maximum number of cached files |
| validate_timestamps |
1 (enabled) |
0 (disabled) |
Check file timestamps for changes |
| revalidate_freq |
2 seconds |
N/A |
Frequency of timestamp checks |
Important: In production, set validate_timestamps = 0 for maximum
performance. This means OPcache won't check for file changes, so you'll need to manually reload
PHP-FPM after code updates.
5. FastCGI Caching
Recommendation for Dynamic Sites: FastCGI caching is not recommended for dynamic
sites due to complications with cache exclusions. It's better suited for static sites. For dynamic
WordPress sites, consider WP Super Cache or W3 Total Cache instead.
HTTP Context Configuration
Navigate to Nginx configuration
cd /etc/nginx
Edit main configuration
sudo nano nginx.conf
Add these directives just above the "Virtual Host Configs" comment:
FastCGI cache configuration
### FASTCGI CACHING
# fastcgi_cache_path directive - PATH & NAME must be unique for each site
fastcgi_cache_path /var/run/SITE levels=1:2 keys_zone=NAME:100m inactive=60m;
# applied to all sites
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;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache NAME;
fastcgi_cache_valid 60m;
Cache Exclusions Configuration
Navigate to includes directory
cd /etc/nginx/includes/
Create exclusions file
sudo nano fastcgi_cache_excludes.conf
Exclusions configuration
# NGINX SKIP CACHE INCLUDE FILE
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
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 use the cache for logged in users or recent commenters
if ($http_cookie ~*
"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
Server Block Configuration
Navigate to sites-available
cd /etc/nginx/sites-available
Edit site configuration
sudo nano example.com.conf
Add these lines to your server block:
Include directives
include /etc/nginx/includes/fastcgi_cache_excludes.conf;
add_header X-FastCGI-Cache $upstream_cache_status;
Cache Purging
Add this location block to enable cache purging (use any name you prefer instead of /purge/):
Purge location block
location ~ /purge(/.*) {
fastcgi_cache_purge NAME "$scheme$request_method$host$1";
}
Test and Apply Configuration
Test Nginx configuration
sudo nginx -t
Reload Nginx
sudo systemctl reload nginx
Restart PHP-FPM
sudo systemctl restart php8.3-fpm
Verify Caching
Check HTTPS response
curl -I https://example.com
Check WWW response
curl -I https://www.example.com
Look for the X-FastCGI-Cache header in the response. Values can be:
- MISS - Response not cached (first request)
- HIT - Response served from cache
- BYPASS - Cache bypassed due to exclusion rules
Removing FastCGI Caching
Edit site configuration
cd /etc/nginx/sites-available
sudo nano example.com.conf
Remove or comment out the following:
Remove these directives
include /etc/nginx/includes/fastcgi_cache_excludes.conf;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache NAME;
fastcgi_cache_valid 60m;
add_header X-FastCGI-Cache $upstream_cache_status;
location ~ /purge(/.*) { ... }
Test and reload
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl restart php8.3-fpm
6. WP Super Cache Configuration
WP Super Cache is a popular WordPress caching plugin that generates static HTML files from your
dynamic WordPress blog. This is one of the recommended solutions for dynamic WordPress sites.
Recommended for Dynamic Sites: WP Super Cache can be combined with object caching
(Redis) to improve site speed and responsiveness while maintaining dynamic content accuracy.
Nginx Cache Exclusions
Navigate to includes directory
cd /etc/nginx/includes/
Create exclusions file
sudo nano wp_super_cache_excludes.conf
WP Super Cache exclusions configuration
# WP Super Cache NGINX Cache Exclusions Rules.
set $cache_uri $request_uri;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $cache_uri 'null cache';
}
if ($query_string != "") {
set $cache_uri 'null cache';
}
# Don't cache uris containing the following segments
if ($request_uri ~*
"(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)")
{
set $cache_uri 'null cache';
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~*
"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $cache_uri 'null cache';
}
# Use cached or actual file if they exists, otherwise pass request to WordPress
location / {
try_files /wp-content/cache/supercache/$http_host/$cache_uri/index-https.html
$uri $uri/ /index.php?$args ;
}
Server Block Configuration
Navigate to sites-available
cd sites-available/
Edit site configuration
sudo nano example.com.conf
Add this include directive:
Include WP Super Cache exclusions
include /etc/nginx/includes/wp_super_cache_exclusions.conf;
Test and reload Nginx
sudo nginx -t
sudo systemctl reload nginx
Uninstalling WP Super Cache
Edit site configuration
cd /etc/nginx/sites-available/
sudo nano example.com.conf
Remove:
Remove include directive
include /etc/nginx/includes/wp_super_cache_exclusions.conf;
Uncomment:
Restore default location block
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
Reload services
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl reload php8.3-fpm
7. W3 Total Cache Configuration
W3 Total Cache (W3TC) is a comprehensive caching plugin that offers advanced caching options and
built-in support for object caching, making it an excellent choice for managing both page caching
and object caching in one solution.
Best Choice for Dynamic Sites: W3TC offers built-in support for Redis, thereby
simplifying the setup process and enabling users to harness the benefits of Redis without the need
for additional plugins or configurations.
Prepare nginx.conf File
Navigate to WordPress directory
cd /var/www/example.com/public_html/
Create nginx.conf file
sudo touch nginx.conf
Set ownership
sudo chown username:username nginx.conf
Set permissions
sudo chmod 660 nginx.conf
Verify permissions
sudo ls -l public_html/
Security Configuration
Navigate to includes directory
cd /etc/nginx/includes/
Edit security directives
sudo nano nginx_security_directives.conf
Add this line to deny access to nginx.conf:
Deny nginx.conf access
location = /nginx.conf { deny all; }
Cache Exclusions Configuration
Create W3TC exclusions file
cd /etc/nginx/includes/
sudo nano w3tc_cache_excludes.conf
W3TC cache exclusions
# ---------------------
# W3 TOTAL CACHE EXCLUDES FILE
# ---------------------
set $cache_uri $request_uri;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $cache_uri 'null cache';
}
if ($query_string != "") {
set $cache_uri 'null cache';
}
# Don't cache uris containing the following segments
if ($request_uri ~*
"(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)")
{
set $cache_uri 'null cache';
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~*
"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $cache_uri 'null cache';
}
# Use cached or actual file if file exists, otherwise pass request to WordPress
location / {
try_files /wp-content/w3tc/pgcache/$cache_uri/_index.html $uri $uri/
/index.php?$args;
}
Server Block Configuration
Edit site configuration
cd /etc/nginx/sites-available/
sudo nano example.com.conf
Comment out the default location block:
Comment default location
#location / {
# try_files $uri $uri/ /index.php$is_args$args;
#}
Add these include directives:
Include W3TC configuration
include /etc/nginx/includes/w3tc_cache_excludes.conf;
include /var/www/example.com/public_html/nginx.conf;
Test and reload
sudo nginx -t
sudo systemctl reload nginx
Install PHP Tidy Extension
Update package list
sudo apt update
Install PHP Tidy
sudo apt install php8.3-tidy
Reload services
sudo systemctl reload nginx
sudo systemctl reload php8.3-fpm
Uninstalling W3TC
Edit site configuration
cd /etc/nginx/sites-available/
sudo nano example.com.conf
Uncomment default location:
Restore location block
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
Remove include directives:
Remove W3TC includes
include /etc/nginx/includes/w3tc_cache_excludes.conf;
include /var/www/example.com/public_html/nginx.conf;
Remove cache files:
Navigate to wp-content
cd /var/www/example.com/public_html/wp-content/
Remove cache directories
sudo rm -rf cache/ w3tc-config/
Remove nginx.conf
cd /var/www/example.com/public_html/
sudo rm nginx.conf
Reload services
sudo systemctl reload php8.3-fpm
sudo systemctl reload nginx
8. Redis Object Cache
Redis is an in-memory data structure store that can be used as a database, cache, and message broker.
When integrated with WordPress, Redis caches database queries and objects, significantly improving
site performance.
Perfect Combination: Redis object caching pairs excellently with WP Super Cache or
W3 Total Cache to provide comprehensive caching coverage for dynamic WordPress sites.
Installation
Update package list
sudo apt update
Install Redis and PHP extension
sudo apt install redis-server php8.3-redis
Verify Installation
Check Redis status
sudo systemctl status redis-server
Check Redis log
sudo cat /var/log/redis/redis-server.log
Fix Memory Overcommit Warning
If you see this warning in the log:
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
Navigate to sysctl.d
cd /etc/sysctl.d/
Create Redis configuration
sudo nano 11-redis.conf
Set overcommit memory
vm.overcommit_memory = 1
Reboot system
sudo reboot
After reboot, verify the fix:
Verify Redis status
sudo systemctl status redis-server
sudo cat /var/log/redis/redis-server.log
Configure Redis Memory Settings
List Redis configuration
cd /etc/
sudo ls redis/
Edit Redis configuration
sudo nano redis/redis.conf
Add or modify these directives:
Memory configuration
maxmemory 256mb
maxmemory-policy allkeys-lru
Restart Redis and reboot
sudo systemctl restart redis-server
sudo reboot
| Setting |
Value |
Description |
| maxmemory |
256mb |
Maximum memory Redis can use |
| maxmemory-policy |
allkeys-lru |
Eviction policy - removes least recently used keys |
| vm.overcommit_memory |
1 |
Allows Redis to allocate more memory than physically available |
WordPress Configuration
Edit wp-config.php
cd /var/www/example.com/public_html/
sudo nano wp-config.php
Add this configuration directive:
Redis cache key salt
define( 'WP_CACHE_KEY_SALT', 'example.com' );
WooCommerce Integration
To prevent Redis from caching WooCommerce session data:
Prevent caching WooCommerce sessions
/** PREVENT REDIS CACHING WOO SESSION DATA */
define('WP_REDIS_IGNORED_GROUPS', 'wc_session');
WooCommerce Cache Exclusions
URLs to exclude from caching:
- /cart/
- /my-account/
- /checkout/
Cookies to exclude from caching:
- woocommerce_cart_hash
- woocommerce_items_in_cart
- wp_woocommerce_session_
- woocommerce_recently_viewed
- store_notice[notice id]
- _wc_session_
9. PHP-FPM Process Manager Optimization
Calculate Memory Requirements
Display pool usernames
grep -E '^\s*user\s*=' /etc/php/8.3/fpm/pool.d/*.conf | awk -F= '{print $2}' |
xargs | tr ' ' '\n' | sort -u
Calculate average memory per process (replace POOL_USER with actual
username)
ps -C php-fpm --user POOL_USER -o rss= | awk '{ sum += $1; count++ } END { if
(count > 0) printf ("%d%s\n", sum/NR/1024,"M") }'
OnDemand Configuration
Navigate to pool directory
cd /etc/php/8.3/fpm/pool.d/
ls
Edit pool configuration
sudo nano example.com.conf
OnDemand process manager settings
pm = ondemand
pm.max_children = as calculated
pm.process_idle_timeout = 10s;
pm.max_requests = 500
Reload PHP-FPM
sudo systemctl reload php8.3-fpm
Monitor Max Children
List log directory
ls /var/log/
Check for max_children warnings
sudo grep max_children /var/log/php8.3-fpm.log
Warning to Watch For:
WARNING: [pool www] server reached max_children setting (25), consider raising it
If you see this warning, increase the pm.max_children value in your pool
configuration.
| Setting |
Description |
Recommended Value |
| pm |
Process manager type |
ondemand |
| pm.max_children |
Maximum child processes |
Based on memory calculation |
| pm.process_idle_timeout |
Time before idle process is killed |
10s |
| pm.max_requests |
Requests before process restart |
500 |
10. Cloudflare Integration
When using Cloudflare as a reverse proxy, Nginx needs to know the real visitor IP addresses.
Configure Nginx to trust Cloudflare's IP ranges and use the CF-Connecting-IP header.
IP Ranges: Keep your Cloudflare IP list updated. Check the official lists at:
Create Cloudflare IP List
Navigate to includes directory
cd /etc/nginx/includes
Create IP list configuration
sudo nano cloudflare_ip_list.conf
Cloudflare IP ranges (Last updated October 2022)
# Last updated OCT 2022
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
Include in Server Block
Navigate to sites-available
cd /etc/nginx/sites-available/
Edit site configuration
sudo nano example.com.conf
Add this include directive in your server block:
Include Cloudflare IP list
include /etc/nginx/includes/cloudflare_ip_list.conf;
Test and reload
sudo nginx -t
sudo systemctl reload nginx
Cloudflare Request Flow
Visitor
Original IP: 1.2.3.4
→
Cloudflare
Proxy IP: 104.16.x.x
→
Nginx
Reads CF-Connecting-IP
→
Result: Nginx will now correctly log visitor IP addresses instead of Cloudflare's
proxy IPs, essential for analytics, security, and access control.