Ludicrous Speed: A Step-by-Step Tutorial to Building a High-Performance WooCommerce VPS with NGINX, Redis, & Cloudflare
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
$nocachemap and Cloudflare bypass rules. - Redis not used: Ensure plugin is enabled and
Object Cacheshows Connected. Checkphp-redisis 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-adminby 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.