You are currently viewing WordPress Nginx FastCGI Cache: 7-Step Guide to PHP-FPM Setup, Bypass & TLS

WordPress Nginx FastCGI Cache: 7-Step Guide to PHP-FPM Setup, Bypass & TLS

  • Post author:
  • Post category:Tutorials
  • Post comments:0 Comments
  • Reading time:5 mins read

Table of Contents

Overview — WordPress Nginx FastCGI Cache

wordpress nginx fastcgi cache php-fpm setup — This guide deploys WordPress on Nginx with FastCGI cache for big performance gains. We’ll set cookie-based cache bypass for logged-in users and comments, enable HTTPS, and add health checks and hardening. All configs are copy-pasteable with heredocs. Reference: Nginx documentation and Let’s Encrypt.

Prerequisites

  • A Linux server with sudo and a public DNS name (DOMAIN).
  • Open ports: 80 (HTTP), 443 (HTTPS).
  • Placeholders to replace: DOMAIN, WEBROOT (e.g., /var/www/wordpress), PHP_SOCK (e.g., /run/php/php-fpm.sock).
  • Distros covered: Ubuntu/Debian, RHEL-family (RHEL/Rocky/CentOS Stream/Fedora), Arch/Manjaro, openSUSE/SLE.

Quick Architecture

Client -> Nginx (TLS + FastCGI cache) -> PHP-FPM -> WordPress (files + DB)
                           ^ bypass cache for logged-in/comments via cookies

Install / Setup — WordPress on Nginx (PHP-FPM + FastCGI Cache)

1) Install Nginx, PHP-FPM, and Certbot (for HTTPS).

Ubuntu/Debian

sudo apt update
sudo apt install -y nginx php-fpm php-mysql php-xml php-gd php-curl php-zip php-mbstring mariadb-client
sudo apt install -y certbot python3-certbot-nginx

RHEL-Family (RHEL/Rocky/CentOS Stream/Fedora)

sudo dnf -y install nginx php-fpm php-mysqlnd php-xml php-gd php-curl php-zip php-mbstring mariadb-connector-c
sudo dnf -y install certbot python3-certbot-nginx
# Enable PHP-FPM service name can vary (php-fpm):
sudo systemctl enable --now php-fpm

Arch / Manjaro

sudo pacman -Sy --noconfirm nginx php-fpm php-gd php-curl php-zip php-mysqli mariadb-clients certbot
sudo systemctl enable --now php-fpm

openSUSE / SLE

sudo zypper refresh
sudo zypper install -y nginx php8-fpm php8-mysql php8-xml php8-gd php8-curl php8-zip php8-mbstring mariadb-tools certbot python3-certbot-nginx
sudo systemctl enable --now php-fpm

2) Create the cache path and base tuning snippet.

# Cache path & map rules (one-time)
sudo tee /etc/nginx/conf.d/wordpress-cache.conf > /dev/null <<'NGINC'
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=WP:200m inactive=60m use_temp_path=off;

# Bypass cache for logged-in & commenters
map $http_cookie $skip_cache {
  default 0;
  "~*wordpress_logged_in_" 1;
  "~*comment_author" 1;
  "~*woocommerce_items_in_cart|woocommerce_cart_hash|wp-postpass_" 1;
}

# Bypass via query flag
map $arg_nocache $query_nocache {
  default 0;
  "1" 1;
  "true" 1;
}
NGINC
sudo mkdir -p /var/cache/nginx/fastcgi && sudo chown -R www-data:www-data /var/cache/nginx/fastcgi 2>/dev/null || sudo chown -R nginx:nginx /var/cache/nginx/fastcgi 2>/dev/null || true

3) Obtain Let’s Encrypt certificates (auto HTTPS).

sudo certbot --nginx -d DOMAIN -d www.DOMAIN --redirect -m admin@DOMAIN --agree-tos --non-interactive
sudo systemctl enable --now certbot.timer 2>/dev/null || sudo systemctl enable --now certbot-renew.timer 2>/dev/null || true

Base Configuration

4) WordPress vhost with FastCGI cache and cookie-based bypass (copy as one block). Replace DOMAIN, WEBROOT, PHP_SOCK.

# /etc/nginx/conf.d/DOMAIN.conf
sudo tee /etc/nginx/conf.d/DOMAIN.conf > /dev/null <<'NGINX'
server {
  listen 443 ssl http2;
  listen 443 quic reuseport;
  server_name DOMAIN www.DOMAIN;

  root WEBROOT;
  index index.php index.html;

  ssl_certificate     /etc/letsencrypt/live/DOMAIN/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem;
  add_header Alt-Svc 'h3=":443"; ma=86400' always;

  # Static
  location ~* \.(?:css|js|jpg|jpeg|gif|png|webp|ico|svg|ttf|otf|woff|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, max-age=2592000, immutable";
    try_files $uri =404;
  }

  # PHP front controller
  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:PHP_SOCK;

    # Cache key and rules
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    set $bypass 0;
    if ($skip_cache) { set $bypass 1; }
    if ($request_method = POST) { set $bypass 1; }
    if ($query_nocache = 1) { set $bypass 1; }

    fastcgi_no_cache $bypass;
    fastcgi_cache_bypass $bypass;
    fastcgi_cache WP;
    fastcgi_cache_valid 200 301 302 1h;
    add_header X-Cache $upstream_cache_status always;
  }

  # Deny access to sensitive files
  location ~* /\.(ht|git) { deny all; }
}

server {
  listen 80;
  server_name DOMAIN www.DOMAIN;
  return 301 https://$host$request_uri;
}
NGINX

sudo nginx -t && sudo systemctl reload nginx

5) PHP-FPM socket path quick reference per distro.

  • Ubuntu/Debian: `/run/php/php-fpm.sock` or `/run/php/php8.1-fpm.sock` (check `ls /run/php/`)
  • RHEL-Family: `/run/php-fpm/www.sock`
  • Arch/Manjaro: `/run/php-fpm/php-fpm.sock`
  • openSUSE/SLE: `/run/php-fpm/php-fpm.sock` or versioned

Reload/Enable & Health Checks

6) Health checks and quick validation.

sudo nginx -t && sudo systemctl reload nginx
systemctl --no-pager --full status php-fpm | sed -n '1,40p'
curl -I https://DOMAIN | sed -n '1,20p'
# Warm and test cache:
curl -I https://DOMAIN/ | grep -i x-cache
curl -I https://DOMAIN/?nocache=1 | grep -i x-cache

Security / Hardening

# Firewall examples (limit where possible)
sudo ufw allow 80/tcp 2>/dev/null || true
sudo ufw allow 443/tcp 2>/dev/null || true
sudo ufw allow 443/udp 2>/dev/null || true
sudo ufw enable 2>/dev/null || true

# systemd drop-in for php-fpm and nginx (optional hardening)
sudo mkdir -p /etc/systemd/system/nginx.service.d /etc/systemd/system/php-fpm.service.d 2>/dev/null || true
sudo tee /etc/systemd/system/nginx.service.d/override.conf > /dev/null <<'OVR'
[Service]
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
OVR
sudo tee /etc/systemd/system/php-fpm.service.d/override.conf > /dev/null <<'OVR2'
[Service]
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
OVR2
sudo systemctl daemon-reload && sudo systemctl restart nginx php-fpm || true

Performance & Optimization — for WordPress on Nginx

  • Ensure OPcache is enabled in PHP for faster PHP execution.
  • Cache only GET/HEAD; avoid caching POST or query-string heavy endpoints.
  • Bypass cache for logged-in and cart sessions to prevent stale personalized content.

7) Optional: enable Brotli (if available) or keep gzip for text assets.

Backup & Restore

sudo tar czf wp-nginx-cache-backup-$(date +%F).tgz   /etc/nginx/conf.d /etc/nginx/nginx.conf /var/www   /etc/letsencrypt /var/cache/nginx/fastcgi

# Restore:
# sudo tar xzf wp-nginx-cache-backup-YYYY-MM-DD.tgz -C /
# sudo nginx -t && sudo systemctl reload nginx

Troubleshooting (Top issues)

1) X-Cache is always MISS — PHP socket path wrong or cache bypass matched.

grep -n 'fastcgi_pass' /etc/nginx/conf.d/DOMAIN.conf; ls -l /run/php* /run/php-fpm* 2>/dev/null || true

2) Logged-in pages get cached — check cookie rules in the map.

grep -n 'map $http_cookie' /etc/nginx/conf.d/wordpress-cache.conf; nginx -t

3) 502 Bad Gateway — PHP-FPM down or socket path wrong.

systemctl status php-fpm | sed -n '1,60p'

4) Certbot fails — DNS not propagated or port 80 blocked.

dig +short DOMAIN; curl -I http://DOMAIN | head -n1

Key Takeaways & Next Steps

  • wordpress nginx fastcgi cache php-fpm setup best practices across major Linux distros.
  • FastCGI cache significantly reduces PHP load and TTFB for anonymous traffic.
  • Bypass rules protect logged-in/checkout flows; add nocache flag for debugging.
  • Next: add cache purge hooks via deploy webhooks or wp-cli after content updates.

Leave a Reply