📋 Introduction to FastCGI Caching
FastCGI caching for WordPress dramatically enhances site performance by caching dynamic content generated by PHP scripts. This reduces server load and database queries, leading to faster page load times and improved user experience.
💡 Key Benefits
- Performance Enhancement: Significantly reduces page load times by serving cached content
- Reduced Server Load: Minimizes PHP processing and database queries
- Robust Architecture: Continues serving content even if PHP-FPM crashes
- Scalability: Handles high traffic volumes efficiently
🔄 FastCGI Caching Flow
If cache exists: Serve from cache (HIT) | If cache missing: Query PHP-FPM (MISS)
⚠️ Understanding the Permissions Challenge
Due to site hardening implementations, WordPress caching plugins cannot delete server-side FastCGI cache files. This occurs because:
- The site runs as a different user than the web server
- Cached files created by NGINX are owned by the web server user
- The PHP pool user, although added to the web server group, has no permissions on cached files
⚡ Permission Issue Breakdown
Directory Ownership: Owner: www-data | Group: root
Permissions: rwx------ (Only owner has read/write/execute)
This makes it impossible for WordPress plugins to clear the cache, as the group has no permissions on the files.
🔧 Solutions Available
- Command-line purging: Enable selective purging via bash scripts
- Alternative approach: Use caching plugins like WP Super Cache or W3 Total Cache
- Client sites: Recommended to use caching plugins for easier administration
⚙️ FastCGI Cache Configuration
Step 1: Configure HTTP Context in nginx.conf
First, edit the main NGINX configuration file:
Position your cursor above the # Virtual Host Configs comment and add the following
directives:
🔍 Important Configuration Notes
| Directive | Description | Example Value |
|---|---|---|
| Path | Location of cache storage (must be unique per site) | /var/run/example |
| levels | Subdirectory structure for cache files | 1:2 |
| keys_zone | Unique name to identify cache memory zone | NAME:100m |
| inactive | Time before unused cache is removed | 60m |
📝 Example Configuration for Your First Site
Replace SITE with your site identifier (e.g., "example") and NAME with a
unique cache zone name:
Test the configuration (do NOT reload yet):
Step 2: Create Cache Exclusion Rules
Create a file to define which content should not be cached:
Add the following exclusion rules:
Step 3: Configure Server Block
Edit your site's NGINX server block configuration:
Add the include directive near the top of the server block:
In the PHP processing location block, add FastCGI caching directives:
⚠️ Important: Replace NAME with the exact keys_zone name you
specified in nginx.conf (e.g., "example").
Step 4: Test and Enable Configuration
Test the NGINX configuration:
If the test is successful, reload NGINX:
🔍 Verifying Cache Status
Use the curl command to check if FastCGI caching is working properly:
Look for the X-FastCGI-Cache header in the response. You will receive one of three
statuses:
Cache Status Responses
| Status | Description | Meaning |
|---|---|---|
| HIT | Content served from cache | Page was found in cache and served directly by NGINX |
| MISS | Cache not found | Page wasn't cached and was generated by PHP-FPM |
| BYPASS | Cache intentionally skipped | Page matched exclusion rules (e.g., /wp-admin/) |
Testing Cache Behavior
Test 1: Homepage
First request: X-FastCGI-Cache: MISS
Second request: X-FastCGI-Cache: HIT
Test 2: Admin Area (Should Bypass)
Expected result: X-FastCGI-Cache: BYPASS
Test 3: Individual Post
First request: X-FastCGI-Cache: MISS
Second request: X-FastCGI-Cache: HIT
✅ Expected Workflow
- Create a new WordPress post
- First curl request to post URL returns MISS
- Second curl request returns HIT
- Subsequent requests continue to return HIT
🗑️ Selective Cache Purging
Add a location block to enable manual cache purging for specific URLs:
Add the following location block inside your server block:
Note: Replace NAME with your keys_zone name. You can use any path
for purging (e.g., /purge/, /clear/, etc.).
Test and reload:
How to Purge Specific Pages
To purge a specific page from cache, visit:
To purge the homepage:
🔧 Additional WordPress Optimizations
Post Revisions Management
Disable or limit post revisions to reduce database bloat:
Add before the "That's all, stop editing!" line:
Memory Limit Configuration
Increase PHP memory limit for WordPress:
Add or modify:
Also add to wp-config.php:
WP-Cron Optimization
Disable default WP-Cron and use system cron:
Set up system cron job:
Add the following line (runs every 15 minutes):
⚡ OPcache Configuration
OPcache improves PHP performance by storing precompiled script bytecode in memory:
Development Server Configuration
Production Server Configuration
🔑 Key Differences
- validate_timestamps: Enable (1) for development, disable (0) for production
- revalidate_freq: Only needed in development (not used in production)
- Production: Disabling timestamp validation provides maximum performance
Calculate appropriate max_accelerated_files value:
Set max_accelerated_files to at least the number of PHP files (rounded up to nearest prime).
Apply changes:
🔄 PHP-FPM Process Management
Calculate Average Memory Usage
First, display pool usernames:
Calculate average memory per process (replace POOL_USER with actual username):
OnDemand Process Manager Configuration
💡 Calculation Formula
max_children = (Available RAM) / (Average Process Memory)
Example: 2GB RAM / 40MB per process = 50 max children (leave room for other processes)
Monitor for warnings:
If you see warnings about reaching max_children, increase the value accordingly.
☁️ Cloudflare Integration
Configure NGINX to properly handle requests proxied through Cloudflare:
Add Cloudflare IP ranges (update regularly from https://www.cloudflare.com/ips/):
Include in your server block:
❌ Removing FastCGI Cache
If you need to disable FastCGI caching:
Step 1: Edit Server Block
Remove or comment out the following lines:
Step 2: Test and Reload
Note: FastCGI cache directives in nginx.conf can remain as they're only used when called from server blocks.
🔌 Alternative Caching Solutions
WP Super Cache Configuration
Create exclusion rules for WP Super Cache:
Include in server block:
W3 Total Cache Configuration
First, create an nginx.conf file in WordPress root:
Secure the nginx.conf file:
Create W3TC cache exclusions:
Update server block:
Install required PHP extension:
🔴 Redis Object Cache
Redis provides object caching for WordPress, reducing database queries:
Installation
Check status:
Fix Overcommit Memory Warning
If you see a warning about overcommit_memory:
Configure Redis Memory
Find and set:
WordPress Configuration
Add before "That's all, stop editing!":
WooCommerce Redis Configuration
For WooCommerce sites, prevent Redis from caching session data:
🛒 WooCommerce Cache Exclusions
Exclude the following pages and cookies from caching:
- Pages: /cart/, /my-account/, /checkout/
- Cookies: woocommerce_cart_hash, woocommerce_items_in_cart, wp_woocommerce_session_, woocommerce_recently_viewed, store_notice[notice id]
✅ Best Practices & Tips
Performance Optimization Checklist
| Component | Recommendation | Impact |
|---|---|---|
| FastCGI Cache | 60m cache validity, 100MB memory | High performance, low resource usage |
| OPcache | 256MB, disable timestamps in production | Significant PHP performance boost |
| Redis | 256MB, allkeys-lru policy | Reduces database queries dramatically |
| PHP-FPM | OnDemand process manager | Efficient memory usage |
Security Considerations
- Always run sites as separate users (not www-data)
- Set appropriate file permissions (660 for config files)
- Secure sensitive files like nginx.conf in WordPress root
- Keep Cloudflare IP lists updated regularly
- Monitor PHP-FPM logs for max_children warnings
Monitoring & Maintenance
Check log files regularly:
Common Issues & Solutions
| Issue | Cause | Solution |
|---|---|---|
| Cache always shows MISS | fastcgi_cache directive not set or incorrect name | Verify keys_zone name matches in nginx.conf and server block |
| Unable to purge cache via plugin | Permission issues | Use command-line purging or switch to caching plugin |
| Server out of memory | Too many cache zones or PHP processes | Reduce cache sizes or max_children value |
| Redis overcommit warning | Kernel parameter not set | Set vm.overcommit_memory = 1 in sysctl |
📊 Summary
🎯 Key Takeaways
- FastCGI Caching: Provides the fastest caching solution for WordPress, serving content even when PHP is down
- Configuration Hierarchy: HTTP context (nginx.conf) → Include files → Server block configuration
- Cache Exclusions: Critical to exclude admin areas, logged-in users, and dynamic content
- Verification: Use curl -I to check X-FastCGI-Cache header (HIT/MISS/BYPASS)
- Alternative Solutions: WP Super Cache and W3 Total Cache offer easier management for client sites
- Complementary Technologies: Combine with OPcache and Redis for maximum performance
- Security: Proper user separation and file permissions are essential