Key Takeaways
- WordPress plugins run inside PHP — they can’t configure your server, which is where the biggest speed gains live
- Upgrading PHP from 7.4 to 8.2+ delivers a 30–50% speed improvement with zero code changes
- Server-level page caching (Nginx FastCGI or Varnish) serves pages in 20ms vs 600ms+ from PHP
- Redis object caching cuts repeated database query times from 50ms to 0.5ms
- Combining these server fixes typically gets TTFB under 200ms and PageSpeed above 95
Why plugins have limits
Every WordPress performance plugin — WP Rocket, LiteSpeed Cache, Autoptimize — runs inside WordPress. That means it executes after PHP has loaded, after WordPress core has bootstrapped, and after the database has been queried. By the time a plugin can do anything, hundreds of milliseconds have already passed.
A plugin can’t upgrade your PHP version. It can’t configure Nginx worker processes. It can’t set up Redis at the system level. It can’t enable Brotli compression on your web server. It can’t tune MySQL buffer sizes. These are server-level operations that require SSH access and knowledge of Linux system administration.
Think of it this way: plugins are like optimising the interior of a car — adjusting mirrors, cleaning the air filter. Server-level work is rebuilding the engine. Both matter, but if your engine is fundamentally slow, no amount of interior work will win the race.
This guide covers the server-level optimisations that plugins simply cannot do. These are the changes that take a WordPress site from a 600ms TTFB to under 100ms, from a PageSpeed score of 50 to 95+. This is exactly what we do for every VeloPress client.
Upgrade PHP to 8.2+
This is the single easiest performance win on this list. PHP 8.2 includes a JIT (Just-In-Time) compiler, improved type handling, and significant performance optimisations over earlier versions. Real-world benchmarks show WordPress running 30–50% faster on PHP 8.2 compared to PHP 7.4 — with zero code changes.

WordPress core has required PHP 7.4+ since version 6.3, but most hosts still allow older versions. If you’re on PHP 7.4, you’re leaving free performance on the table. If you’re on PHP 7.2 or earlier, you’re also missing critical security patches.
# Check your current PHP version
php -v
# On Cloudways, change via the Application Settings panel
# On cPanel, use MultiPHP Manager
# On Plesk, use PHP Settings under the domain
Important: Always test the upgrade on a staging site first. Most modern plugins and themes work fine on PHP 8.2+, but older or unmaintained plugins may throw deprecation notices. Fix or replace those plugins before upgrading production.
Enable and tune OPcache
PHP is an interpreted language — every time a page loads, PHP reads the source files, compiles them to bytecode, and then executes that bytecode. OPcache stores the compiled bytecode in shared memory so PHP skips the compilation step on subsequent requests. On a WordPress site with 50+ PHP files loaded per request, this typically saves 20–40ms per page load.
OPcache is bundled with PHP 5.5+ but often isn’t configured optimally. The default settings allocate too little memory and revalidate files too frequently.
# Recommended OPcache settings for WordPress
# Add to php.ini or a custom opcache.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.fast_shutdown=1
The key settings: memory_consumption=256 gives OPcache enough memory to store all your WordPress files. revalidate_freq=60 tells OPcache to check for file changes every 60 seconds instead of every request. max_accelerated_files=10000 accommodates the thousands of PHP files in a typical WordPress installation with plugins.
Server-level page caching
This is the single biggest performance improvement you can make. Plugin-based page caching (WP Super Cache, WP Rocket) generates static HTML files and serves them via PHP. Server-level page caching (Nginx FastCGI cache or Varnish) serves cached pages directly from the web server, bypassing PHP entirely. For a full breakdown of all four caching layers, see our WordPress caching guide.

The difference is dramatic. A page served via PHP-based caching takes 80–150ms. The same page served from Nginx FastCGI cache takes 10–30ms. That’s a 5–10x improvement, and it’s invisible to WordPress — the cache sits in front of WordPress and intercepts requests before they reach PHP.
Nginx FastCGI cache
# In nginx.conf or your site's server block
# Define the cache zone (outside server block)
fastcgi_cache_path /var/run/nginx-cache levels=1:2
keys_zone=WORDPRESS:100m inactive=60m max_size=512m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# Inside the server block
set $skip_cache 0;
# Don't cache POST requests
if ($request_method = POST) { set $skip_cache 1; }
# Don't cache URLs with query strings
if ($query_string != "") { set $skip_cache 1; }
# Don't cache admin, login, or WooCommerce pages
if ($request_uri ~* "/wp-admin/|/wp-login.php|/cart/|/checkout/|/my-account/") {
set $skip_cache 1;
}
# Don't cache for logged-in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $skip_cache 1;
}
location ~ .php$ {
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
# ... your existing fastcgi_pass directive
}
The X-FastCGI-Cache header lets you verify caching is working — you’ll see HIT on cached pages and MISS on first load or dynamic pages. For WooCommerce sites, the exclusion rules are critical — you never want to cache a logged-in user’s cart or checkout page.
Redis object caching
WordPress runs 80+ database queries per uncached page load. Even with page caching, dynamic pages — WooCommerce product listings, search results, logged-in user dashboards — still hit the database on every request. Redis stores database query results in memory, so repeated queries are served in 0.5ms instead of 50ms.
# Install Redis on Ubuntu/Debian
sudo apt install redis-server
# Start and enable
sudo systemctl start redis-server
sudo systemctl enable redis-server
# Verify it's running
redis-cli ping
# Should return: PONG
# Check memory usage
redis-cli info memory | grep used_memory_human
After installing Redis on the server, you need to connect WordPress to it. Install the Redis Object Cache plugin (by Till Kruess) and activate it. Or, for a plugin-free approach, add this to your wp-config.php:
# Add to wp-config.php (before "That's all, stop editing!")
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0);
define('WP_REDIS_TIMEOUT', 1);
define('WP_REDIS_READ_TIMEOUT', 1);
Then copy the object-cache.php drop-in to wp-content/. For WooCommerce sites, Redis is essential — it caches product query results, session data, and transient data that WooCommerce generates heavily. Our database optimisation guide covers Redis setup and database cleanup in detail.
Brotli compression
Brotli is Google’s compression algorithm, and it’s 15–25% more efficient than Gzip for text-based files. A 400KB CSS file compresses to about 60KB with Brotli versus 80KB with Gzip. Across an entire page with multiple CSS, JS, and HTML files, that difference compounds.
# Nginx — enable Brotli (requires ngx_brotli module)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript
application/json application/xml text/xml
application/xml+rss text/javascript image/svg+xml;
# Apache — enable Brotli (requires mod_brotli)
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css
AddOutputFilterByType BROTLI_COMPRESS application/javascript application/json
AddOutputFilterByType BROTLI_COMPRESS application/xml text/xml
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
BrotliCompressionQuality 6
</IfModule>
Compression level 6 is the sweet spot — it provides excellent compression ratios without significant CPU overhead. Level 11 compresses slightly better but uses dramatically more CPU. Cloudflare enables Brotli automatically on all plans — if you’re using Cloudflare, this is already handled.
HTTP/2 and HTTP/3
HTTP/1.1 downloads files sequentially — the browser queues requests and processes them one at a time per connection (with a typical limit of 6 concurrent connections). HTTP/2 multiplexes all requests over a single connection, allowing dozens of files to download simultaneously. HTTP/3 goes further, using QUIC (a UDP-based protocol) that eliminates head-of-line blocking.
The practical impact: a page loading 40 assets takes dramatically less time over HTTP/2 than HTTP/1.1, because assets download in parallel rather than queuing.
# Nginx — enable HTTP/2 (requires SSL)
listen 443 ssl http2;
# Nginx — enable HTTP/3 (requires OpenSSL 3.0+ or BoringSSL)
listen 443 quic reuseport;
listen 443 ssl http2;
add_header Alt-Svc 'h3=":443"; ma=86400';
HTTP/2 requires HTTPS (SSL), which you should already have. Most modern hosts enable HTTP/2 by default. HTTP/3 support is growing but not universal — Cloudflare enables it automatically, which is the easiest path.
Nginx tuning
Default Nginx settings are conservative — designed to work on any hardware, not optimised for your specific server. Tuning worker processes, connections, and buffer sizes to match your server’s resources can reduce latency by 20–30%.
# /etc/nginx/nginx.conf — optimised for WordPress
# Set worker processes to number of CPU cores
worker_processes auto;
# Increase worker connections (default is 768)
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
http {
# Keepalive connections — reuse TCP connections
keepalive_timeout 30;
keepalive_requests 100;
# Buffer sizes — prevent disk writes for small responses
client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 64m;
large_client_header_buffers 4 16k;
# File sending optimisation
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Gzip settings (as Brotli fallback)
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_vary on;
gzip_types text/plain text/css application/javascript
application/json application/xml text/xml
image/svg+xml;
# Open file cache — avoid repeated disk lookups
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
The critical settings: worker_processes auto matches the number of CPU cores. keepalive_timeout 30 reuses TCP connections instead of opening new ones per request. sendfile on and tcp_nopush on optimise file delivery. The open file cache avoids repeated disk lookups for static files.
DNS optimisation
Every unique domain in your page requires a DNS lookup — typically 20–100ms each. If your page references fonts.googleapis.com, cdn.jsdelivr.net, www.googletagmanager.com, and connect.facebook.net, that’s 4 DNS lookups adding 80–400ms before those resources can start downloading.
<!-- Add to your <head> — DNS prefetch for third-party domains -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//www.google-analytics.com">
<!-- Preconnect for critical third-party resources -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
Better yet: reduce third-party domains entirely. Self-host your fonts instead of loading from Google Fonts. Self-host analytics scripts where possible. Each domain you eliminate saves a DNS lookup, a TCP connection, and a TLS handshake — 100–300ms per domain on mobile.
At the DNS provider level, use a fast provider like Cloudflare DNS (which is free and consistently the fastest in global benchmarks). Slow DNS resolvers can add 50–200ms before the connection to your server even starts.
The result: TTFB under 200ms
Here’s what these changes deliver in practice. On a recent client project, we started with a WordPress site on shared hosting scoring 38 on PageSpeed Insights with a TTFB of 1.4 seconds. After applying the server-level fixes in this guide:
- TTFB: 1,400ms → 85ms (94% reduction)
- PageSpeed Performance: 38 → 97
- Total page load: 6.2s → 1.1s
- Time to Interactive: 8.1s → 1.8s
No WordPress plugins were changed. No content was modified. No theme was replaced. See our hosting performance guide for full benchmark methodology. Every improvement came from server-level work: PHP 8.2 upgrade, OPcache tuning, Nginx FastCGI caching, Redis object cache, Brotli compression, HTTP/2 enabled, and Nginx configuration tuning.
This is exactly what we do for every VeloPress client. If you’re not comfortable SSH’ing into your server and editing Nginx configs, that’s fine — that’s exactly why we exist. Start with our diagnostic guide to identify your specific bottlenecks, then get a free speed audit and we’ll tell you precisely what needs fixing.
Frequently asked questions
Can I speed up WordPress without SSH access?
You can make some improvements — caching plugins, image optimisation, and plugin cleanup don’t require SSH. But the biggest gains (PHP upgrades, server caching, Redis, Nginx tuning) require server access. If your host doesn’t provide SSH, consider managed WordPress hosting like Cloudways, which gives you full server control through a dashboard and SSH.
Is Varnish or Nginx FastCGI cache better for WordPress?
Both deliver excellent results. Nginx FastCGI cache is simpler to configure and doesn’t require a separate service — it’s built into Nginx. Varnish is more flexible with its VCL configuration language but adds operational complexity. For most WordPress sites, Nginx FastCGI cache is the better choice. Varnish shines on high-traffic sites with complex caching rules.
Will these server changes break my WordPress site?
They can if misconfigured. The highest-risk change is page caching — if cache exclusion rules aren’t set correctly, logged-in users might see other users’ cached content. Always test on staging first. PHP upgrades can also break older plugins. The safest approach: make one change at a time, verify, then move to the next.
Do I still need a caching plugin if I have server-level caching?
Not for page caching — server-level caching replaces that entirely. However, some caching plugins offer features beyond page caching: CSS/JS minification, lazy loading, preloading, and database cleanup. You might keep a lightweight plugin for those features while relying on your server for the actual caching. Just don’t run two page caches simultaneously — they’ll conflict.
How much does server-level WordPress optimisation cost?
If you’re doing it yourself, the only cost is your time and potentially a hosting upgrade (£20–50/month for a decent VPS). Professional optimisation services like VeloPress start from £499 for a complete server-level overhaul. The ROI is typically positive within weeks — a 7% conversion increase from faster load times pays for the optimisation many times over on any revenue-generating site.
Want these server-level fixes done for you?
VeloPress handles every server optimisation in this guide
PHP upgrades, Nginx caching, Redis setup, Brotli compression — we configure all of it, and you see the results within days.