This is the no-nonsense WooCommerce performance build your store deserves. We will take a clean VPS, install a lean LEMP stack (NGINX, MariaDB, PHP-FPM), add Redis object caching, wire in smart NGINX rules that respect WooCommerce sessions, and finish with a Cloudflare setup that accelerates static assets while keeping cart and checkout uncached. The result: fast Time To First Byte, resilient page rendering under load, and a platform you can scale. For predictable performance, start on a VPS from ENGINYRING and register a proper domain via ENGINYRING Domains. Agencies standardizing this stack can also leverage Reseller Hosting for multi-client rollouts.

1) Prerequisites

Recommended VPS: 2–4 vCPU, 4–8 GB RAM, fast SSD/NVMe, Ubuntu 22.04 LTS or 24.04 LTS. Heavier stores (1k+ products, heavy traffic or promotions) should aim for 4–8 vCPU and 8–16 GB RAM. Ensure you have a domain (e.g., store.example.com), and that you can point DNS to the server later (we will proxy through Cloudflare).

  • SSH access to the VPS as a sudo user
  • Root or sudo privileges
  • Firewall open for ports 80 and 443
  • Basic familiarity with the shell

Update the system first:

sudo apt update && sudo apt -y upgrade
sudo apt -y install unzip curl git ufw

Enable a basic firewall:

sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable

2) Part 1: Install the LEMP Stack (NGINX, MariaDB, PHP-FPM)

NGINX

sudo apt -y install nginx
sudo systemctl enable --now nginx

MariaDB

sudo apt -y install mariadb-server
sudo systemctl enable --now mariadb
sudo mysql_secure_installation

Create a database and a user for WordPress:

sudo mysql -e "CREATE DATABASE wp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;"
sudo mysql -e "CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'STRONG_DB_PASSWORD_HERE';"
sudo mysql -e "GRANT ALL PRIVILEGES ON wp.* TO 'wpuser'@'localhost'; FLUSH PRIVILEGES;"

Baseline MariaDB tuning for VPS (edit /etc/mysql/mariadb.conf.d/50-server.cnf):

[mysqld]
innodb_buffer_pool_size = 1G
innodb_log_file_size    = 256M
innodb_flush_method     = O_DIRECT
max_connections         = 200
query_cache_type        = 0
query_cache_size        = 0
tmp_table_size          = 128M
max_heap_table_size     = 128M

Adjust sizes to your RAM (for 8 GB RAM, try 2–3G buffer pool). Restart MariaDB:

sudo systemctl restart mariadb

PHP-FPM

Install PHP 8.2 or 8.3 with common extensions for WooCommerce:

sudo apt -y install php-fpm php-cli php-mysql php-curl php-xml php-zip php-gd php-mbstring php-intl php-bcmath php-imagick

OPcache and PHP-FPM pool tweaks (edit /etc/php/*/fpm/php.ini):

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
realpath_cache_size=4096k
realpath_cache_ttl=600

Pool sizing (edit /etc/php/*/fpm/pool.d/www.conf), for 4 vCPU and 8 GB RAM as example:

pm = dynamic
pm.max_children = 24
pm.start_servers = 6
pm.min_spare_servers = 6
pm.max_spare_servers = 12
pm.max_requests = 500

Reload PHP-FPM:

sudo systemctl restart php*-fpm

3) Part 2: Performance Tuning with Redis and Smart NGINX Caching

Install and enable Redis

sudo apt -y install redis-server php-redis
sudo sed -i 's/^# maxmemory .*/maxmemory 256mb/' /etc/redis/redis.conf
sudo sed -i 's/^# maxmemory-policy .*/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf
sudo systemctl enable --now redis-server
sudo systemctl restart php*-fpm

Later, in WordPress, install the Redis Object Cache plugin and click Enable. This reduces database calls and speeds up dynamic pages.

NGINX server block with WooCommerce-aware caching

Create a site config at /etc/nginx/sites-available/store.conf (replace the domain):

map $http_cookie $nocache {
    default                    0;
    ~wordpress_logged_in_      1;
    ~comment_author            1;
    ~woocommerce_cart_hash     1;
    ~woocommerce_items_in_cart 1;
    ~wp_woocommerce_session_   1;
}

upstream php-handler {
    server unix:/run/php/php-fpm.sock;
}

server {
    listen 80;
    server_name store.example.com;
    root /var/www/store/current;

    index index.php;
    client_max_body_size 64M;

    # Gzip for text assets
    gzip on;
    gzip_types text/plain text/css application/json application/javascript application/xml+rss application/xml image/svg+xml;
    gzip_vary on;
    gzip_min_length 1024;

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

    # Deny direct access to sensitive files
    location ~* /(\.git|\.env|composer\.(json|lock)|readme\.html|license\.txt) { deny all; }

    # PHP handling + microcache for anonymous
    set $skip_cache $nocache;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 120s;

        # Microcache keys
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;

        # Bypass cache when logged in or WooCommerce session present
        fastcgi_no_cache $skip_cache;
        fastcgi_cache_bypass $skip_cache;

        # Cache for anonymous
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 301 302 10s;
        fastcgi_cache_use_stale updating error timeout invalid_header http_500;
        add_header X-FastCGI-Cache $upstream_cache_status;

        fastcgi_pass php-handler;
    }

    # Let’s Encrypt HTTP-01
    location ^~ /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
        default_type "text/plain";
        try_files $uri =404;
    }
}

Define the FastCGI cache zone (edit /etc/nginx/nginx.conf or a file in /etc/nginx/conf.d/):

fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:100m inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

Enable the site:

sudo mkdir -p /var/www/store/current
sudo chown -R www-data:www-data /var/www/store
sudo ln -s /etc/nginx/sites-available/store.conf /etc/nginx/sites-enabled/store.conf
sudo nginx -t && sudo systemctl reload nginx

Why this works: cart, checkout, and logged-in sessions skip microcaching so users always see fresh totals and stock. Anonymous category and product pages get a short cache to absorb spikes and improve TTFB.

4) Part 3: Install and Secure WordPress + WooCommerce

Install WP-CLI and WordPress core into /var/www/store/current:

cd /tmp
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

cd /var/www/store/current
sudo -u www-data wp core download
sudo -u www-data wp config create --dbname=wp --dbuser=wpuser --dbpass=STRONG_DB_PASSWORD_HERE --dbhost=localhost --dbprefix=wp_
sudo -u www-data wp core install --url="http://store.example.com" --title="Woo Store" --admin_user="admin" --admin_password="STRONG_WP_ADMIN_PASS" --admin_email="you@example.com"

Harden wp-config.php (add below lines with sudo -u www-data wp config set or edit file):

define('DISALLOW_FILE_EDIT', true);
define('AUTOSAVE_INTERVAL', 120);
define('WP_POST_REVISIONS', 10);
define('EMPTY_TRASH_DAYS', 7);
define('WP_CACHE', true);
define('WP_MEMORY_LIMIT', '256M');

Install WooCommerce and must-have plugins:

sudo -u www-data wp plugin install woocommerce --activate
sudo -u www-data wp plugin install redis-cache --activate
sudo -u www-data wp plugin install wp-crontrol --activate
# Optional during build: sudo -u www-data wp plugin install query-monitor
sudo -u www-data wp theme install storefront --activate

Enable Redis object cache inside WP Admin or via WP-CLI:

sudo -u www-data wp redis enable

File permissions (secure defaults):

sudo find /var/www/store -type d -exec chmod 755 {} \;
sudo find /var/www/store -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data /var/www/store

Get a free TLS certificate:

sudo apt -y install certbot python3-certbot-nginx
sudo certbot --nginx -d store.example.com --redirect --agree-tos -m you@example.com -n

Update WordPress Site Address and WordPress Address to https in Settings, or via WP-CLI:

sudo -u www-data wp option update home 'https://store.example.com'
sudo -u www-data wp option update siteurl 'https://store.example.com'

5) Part 4: Configure Cloudflare for Caching and Security

Create a free Cloudflare account, add your domain, and set the nameservers as instructed. In the dashboard:

  • DNS: Set your A record for store.example.com to your server IP and turn the orange cloud ON (proxied).
  • SSL/TLS: Mode = Full (strict). Enable TLS 1.3 and Early Hints. Turn on Always Use HTTPS and HSTS if you understand the implications.
  • Speed: Enable Brotli and HTTP/2 + HTTP/3.
  • Caching: Caching Level = Standard. Create rules to cache static paths and bypass HTML where needed.

Cache Rules (or Page Rules) for WooCommerce

  • Bypass cache on cookie for:
    woocommerce_items_in_cart
    woocommerce_cart_hash
    wp_woocommerce_session_
    wordpress_logged_in_

  • Bypass cache on URL:
    *store.example.com/wp-admin/*
    *store.example.com/wp-login.php*
    *store.example.com/cart*
    *store.example.com/checkout*
    *store.example.com/my-account*

  • Cache static:
    *store.example.com/wp-content/*  (Edge TTL: hours-days)
    *store.example.com/wp-includes/* (Edge TTL: hours-days)

Optional: Cloudflare APO for WordPress (paid) can accelerate HTML for anonymous visitors; keep bypass rules for WooCommerce pages intact.

6) Verification: Benchmark Your Before-and-After

Warm up caches by visiting a few category and product pages while logged out. Then benchmark:

  • Local TTFB check:
    curl -s -o /dev/null -w "TTFB: %{time_starttransfer}\n" https://store.example.com/

  • Load testing (light, from the VPS) using siege:
    sudo apt -y install siege
    siege -c 20 -t 2M https://store.example.com/

  • Remote tests: run WebPageTest or Lighthouse from a workstation and compare First Contentful Paint, Largest Contentful Paint, and TTFB.

Expected outcomes: sub-100 ms TTFB on cached anonymous hits, snappy category navigation, and stable checkout (uncached) under moderate load. If results are weak, scale vCPU/RAM, verify Redis is in use, and re-check cache bypass rules.

7) Common Errors and Fixes

  • 502 Bad Gateway: PHP-FPM crashed or pool too small. Increase pm.max_children; check /var/log/php*/fpm/ and /var/log/nginx/error.log.
  • Cart totals do not update: Something is caching WooCommerce pages. Re-check NGINX $nocache map and Cloudflare bypass rules.
  • Redis not used: Ensure plugin is enabled and Object Cache shows Connected. Check php-redis is installed and Redis service running.
  • Mixed content warnings: Enforce https Site URL, update hardcoded image/script links, and consider a search-replace for http to https.
  • Admin is slow: Admin is intentionally uncached. Trim heavy plugins, disable unused WooCommerce features, update PHP to 8.2/8.3, and increase OPcache memory.
  • High CPU at peak: Increase the FastCGI cache duration slightly (e.g., 20–30s), enable Cloudflare caching for static assets, and add more vCPU.

Operational Playbook

  • Backups: Database dumps nightly, file backups daily; test restores monthly.
  • Updates: Patch Ubuntu, NGINX, PHP, MariaDB monthly; keep WooCommerce and extensions current.
  • Monitoring: Track disk I/O, CPU steal, Redis hit rate, PHP-FPM slow logs, and NGINX cache hit ratios.
  • Security: Strong SSH keys, fail2ban, restrict /wp-admin by IP if possible, and use a WAF (Cloudflare) with sane rules.

Scale Up With Confidence

If your promotions routinely spike traffic, start with adequate headroom. All ENGINYRING VPS plans scale smoothly; agencies managing multiple stores can package this stack as a standard and deploy it repeatedly. For simpler sites or microsites around your store, premium web hosting can complement your setup.

Appendix: Quick Commands Reference

  • Service control:
    sudo systemctl status nginx mariadb php*-fpm redis-server
    sudo systemctl reload nginx
    sudo systemctl restart php*-fpm

  • Clear NGINX cache:
    sudo rm -rf /var/cache/nginx/wordpress/* && sudo systemctl reload nginx

  • Flush Redis (careful in production):
    redis-cli FLUSHALL

  • WP-CLI essentials:
    sudo -u www-data wp plugin list
    sudo -u www-data wp transient delete --all
    sudo -u www-data wp wc tool run regenerate_product_lookup_tables --user=admin

Source & Attribution

This article is based on original data belonging to ENGINYRING.COM blog. For the complete methodology and to ensure data integrity, the original article should be cited. The canonical source is available at: Ludicrous Speed: A Step-by-Step Tutorial to Building a High-Performance WooCommerce VPS with NGINX, Redis, & Cloudflare.