A slow WordPress site is almost never slow because of the server. It is slow because PHP is running on defaults, nothing is cached, and the images are the size they came off the camera. Here is the order we fix these in, from biggest win to smallest.
1. Switch to PHP-FPM and the newest PHP
In Plesk, go to Websites & Domains → PHP Settings for the domain. Set:
- PHP version: the newest your plugins support. 8.3 runs typical WordPress ~30% faster than 7.4.
- Run PHP as: FPM application served by nginx.
Then check the version from the command line, if you have shell access:
plesk bin domain --info example.com | grep -i php
/opt/plesk/php/8.3/bin/php -v2. Turn on OPcache
OPcache keeps compiled PHP in memory so every request does not re-read every file. Under PHP Settings → Performance settings, or in the Additional directives box:
opcache.enable=1
opcache.memory_consumption=192
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
memory_limit=256Mrevalidate_freq=60 means a file edit shows within a minute; set it to 0 on a staging site where you change code constantly.
3. Let Nginx serve static files and cache pages
Under Apache & nginx Settings, tick Serve static files directly by nginx and enable nginx caching with a 5-minute timeout. Nginx then answers the vast majority of hits without PHP starting at all.
If the site has a login area, exclude it so users never see each other's pages. In Additional nginx directives:
# Never cache logged-in users or the cart
if ($http_cookie ~* "wordpress_logged_in|woocommerce_items_in_cart") {
set $no_cache 1;
}Check a page is coming from cache by looking at the response headers:
curl -sI https://example.com/ | grep -i "x-cache\|cache-control"4. Compress the images that are already uploaded
New uploads can be handled by a plugin, but the existing library is where the weight is. From a shell, convert everything to WebP alongside the originals:
cd ~/httpdocs/wp-content/uploads
find . -type f \( -iname '*.jpg' -o -iname '*.png' \) -size +100k \
-exec sh -c 'cwebp -quiet -q 82 "$1" -o "${1%.*}.webp"' _ {} \;
du -sh .Then let Nginx hand out the .webp when the browser accepts it:
location ~* ^/wp-content/uploads/.+\.(png|jpe?g)$ {
add_header Vary Accept;
try_files $uri$webp_suffix $uri =404;
}5. Clean the database
Post revisions, transients and spam comments accumulate for years. Once, from Databases → phpMyAdmin, or with WP-CLI:
wp post delete $(wp post list --post_type='revision' --format=ids) --force
wp transient delete --all
wp comment delete $(wp comment list --status=spam --format=ids)
wp db optimizeThen limit future revisions in wp-config.php:
define('WP_POST_REVISIONS', 5);
define('AUTOSAVE_INTERVAL', 120);6. Put a CDN in front
Cloudflare's free plan is enough for most sites. Point the nameservers at Cloudflare, set SSL mode to Full (strict), and turn on Auto Minify and Brotli. Static files then come from a node near the visitor rather than from London every time.
Measure before and after
Do not guess. Run the site through PageSpeed Insights before you start and after each step, and keep the numbers. The metric that matters is Largest Contentful Paint; under 2.5 seconds is the target.
| Step | Typical LCP gain |
|---|---|
| PHP-FPM + PHP 8.3 | 0.3–0.6 s |
| OPcache | 0.2–0.4 s |
| Nginx page cache | 0.5–1.5 s |
| WebP images | 0.5–2 s on image-heavy pages |
| Database cleanup | small, but stops slow admin pages |
| CDN | 0.2–0.8 s for visitors far from the server |
Every VPSPioneer shared plan already runs PHP-FPM with OPcache and Nginx caching on; steps 1–3 are done for you. On a managed VPS we tune all six as part of setup.