FastCGI Cache Guide
AidiPanel uses Nginx FastCGI Cache — a built-in Nginx feature that caches PHP responses as files on disk, so a separate caching daemon is not needed.
How It Works
Browser request
│
▼
Nginx FastCGI Cache ──── HIT ────► Return cached response (microseconds)
│
MISS
│
▼
PHP-FPM processes request
│
▼
Response cached to disk → sent to browserCache hit = PHP never runs. Response served from disk in ~1ms.
Cache miss = PHP runs normally, response cached for next visitor.
Cache Configuration
The cache zone is defined in /etc/nginx/nginx.conf:
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=aidipanel_fcgi:200m
max_size=10g
inactive=60m
use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;
fastcgi_cache_lock on;Key settings:
| Setting | Value | Meaning |
|---|---|---|
keys_zone | 200m | 200MB RAM for cache index (~1.6M entries) |
max_size | 10g | Max 10GB disk cache |
inactive | 60m | Remove uncached entries after 60 min |
use_temp_path=off | — | Write directly to cache dir (faster) |
Cache Exclusion Rules
Located in /etc/nginx/snippets/fastcgi-cache.conf, included in every vhost:
set $skip_cache 0;
# Skip POST requests (form submissions)
if ($request_method = POST) { set $skip_cache 1; }
# Skip URLs with query strings (?page=2)
if ($query_string != "") { set $skip_cache 1; }
# Skip WordPress admin/login/cart/checkout
if ($request_uri ~* "(/wp-admin/|/wp-login.php|/cart|/checkout|/my-account)") {
set $skip_cache 1;
}
# Skip for logged-in WordPress users
if ($http_cookie ~* "(wordpress_logged_in|woocommerce_items_in_cart)") {
set $skip_cache 1;
}Per-Site Cache Config
Each site's PHP block includes these directives:
fastcgi_cache aidipanel_fcgi;
fastcgi_cache_valid 200 301 302 1h; # Cache 200/301/302 for 1 hour
fastcgi_cache_valid 404 1m; # Cache 404s for 1 minute
fastcgi_cache_bypass $skip_cache; # Skip cache when $skip_cache=1
fastcgi_no_cache $skip_cache; # Don't store when $skip_cache=1The response header X-FastCGI-Cache: HIT|MISS|BYPASS|EXPIRED tells you cache status.
Managing Cache via CLI
# Check cache status and hit rate
aidipanel cache:status
# Purge entire cache
aidipanel cache:purge
# Purge cache for one domain
aidipanel cache:purge --domain example.com
# Disable cache for a domain
aidipanel cache:disable --domain example.com
# Re-enable cache
aidipanel cache:enable --domain example.comManaging Cache via Web Panel
- Log into the panel at
https://<server-ip>:8443 - Go to Cache in the panel
- View hit rate, total cached files, and per-domain status
- Use Purge to clear cache for a domain or all domains
Checking Cache Status with curl
# First request — MISS (PHP runs)
curl -I https://example.com/
# X-FastCGI-Cache: MISS
# Second request — HIT (served from disk)
curl -I https://example.com/
# X-FastCGI-Cache: HITWordPress-Specific: Nginx Cache Purge Plugin
FastCGI cache is opt-in per site. For WordPress sites, AidiPanel can install Nginx Helper and Redis Object Cache only when the user enables cache and explicitly selects those helper options.
aidipanel cache:enable --domain example.com --install-nginx-helper --install-redis-pluginIn wp-config.php:
define('RT_WP_NGINX_HELPER_CACHE_PATH', '/var/cache/nginx/fastcgi');When does the cache auto-purge?
Nginx Helper clears a page from the FastCGI cache only when its content is published or updated (creating/editing a post or page). It does not auto-purge on:
- menu, widget, or Customizer changes,
- theme switches or theme-option edits,
- plugin install / activate / update.
After any of those, the old page can still be served until it expires. Clear it yourself with the Purge button (or aidipanel cache:purge --domain <domain>), or simply wait for the cache TTL (fastcgi_cache_valid) to lapse. The page cache only ever serves anonymous traffic, so the exposure is a stale public page, never private data.
Adjusting Cache Duration
Edit the site's Nginx config in /etc/nginx/sites-available/<domain>.conf:
# Cache for 4 hours instead of 1
fastcgi_cache_valid 200 301 302 4h;Then reload: systemctl reload nginx
Cache Directory
/var/cache/nginx/fastcgi/
├── a/
│ └── 3f/
│ └── a3f8c2e1b4... (cached PHP response)
├── b/
│ └── ...The cache uses a 2-level directory structure (levels=1:2) for efficient filesystem lookups.
Manual purge:
# Purge all
find /var/cache/nginx/fastcgi -type f -delete
# Purge one domain's cache (less precise, purge all and let it rebuild)
aidipanel cache:purge --domain example.comPerformance Tips
- Keep cache TTL high for static content sites (1h–24h)
- Keep cache TTL low for frequently updated sites (5–15min)
- Use Redis Object Cache for WordPress alongside FastCGI Cache — they complement each other:
- FastCGI Cache: page-level caching (full HTML response)
- Redis Object Cache: database query caching inside PHP
- Exclude WooCommerce cart/checkout — already done by default snippet
- Monitor with
aidipanel cache:statusto ensure high hit rate (>80% is good)
Dedicated cache zones (noisy neighbour)
By default every site shares one FastCGI cache zone (aidipanel_fcgi, 200m keys / 10g disk). The cache key is host-scoped, so entries never collide between sites — but the eviction budget is shared, so a very busy site can evict a quieter site's cached pages.
For a noisy or high-traffic site you can give it its own dedicated zone (its own keys_zone + max_size + cache directory), so its eviction is contained:
# give a site its own zone (defaults: 32m keys / 2g disk)
aidipanel cache:zone --action enable --domain example.com
# custom budget
aidipanel cache:zone --action enable --domain example.com --keys 64m --max-size 5g
# inspect
aidipanel cache:zone --action status --domain example.com
# revert to the shared zone (tears the dedicated zone down)
aidipanel cache:zone --action disable --domain example.comNotes:
- Opt-in. It is not a default and most sites don't need it.
- The page cache must already be enabled (
cache:enable) first. - A dedicated zone is additive RAM/disk on top of the shared zone.
enablerefuses if there isn't enough free disk / RAM (override on the CLI with--force; the panel never forces — it asks you to use a smaller size instead). - Zones are declared per-site under
/etc/nginx/aidipanel/cache-zones/and loaded via a shim in/etc/nginx/conf.d/; enabling/disabling never editsnginx.confand is validated withnginx -t+ rollback.