Scale up as you grow — whether you're running one virtual machine or ten thousand.

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.
Hi there,
Good that you are optimizing before scaling, that is the right order.
For PHP-FPM, the key setting is pm.max_children which should be based on how much RAM each PHP process uses. Check your average process size first:
ps --no-headers -o "rss,cmd" -C php-fpm8.x | awk '{ sum+=$1 } END { print sum/NR/1024 " MB average" }'
Then divide your available RAM by that number. A rough starting point for a 2GB Droplet with Redis already handling object cache:
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500
For downloads specifically, the CPU spike is often not PHP at all but Nginx serving large files. Make sure you are using X-Accel-Redirect to let Nginx handle file delivery directly rather than routing downloads through PHP/WordPress:
location /protected-downloads/ {
internal;
alias /var/www/your-files/;
}
For DigitalOcean monitoring alerts, CPU above 80% for 5 minutes is a useful threshold that avoids false alarms from short spikes. Memory above 85% is worth watching too since WordPress with Redis can creep up. You can set these under Manage > Monitoring in the control panel.
On Redis, make sure you are also using a page cache plugin like WP Rocket or W3 Total Cache with full page caching enabled, not just object caching. Object caching alone still runs PHP for every request, full page caching serves cached HTML directly from Nginx and bypasses PHP entirely for repeat visitors.
Hi there,
Bobby’s PHP-FPM sizing and X-Accel-Redirect points are the right foundation for a downloads site, worth building on rather than repeating.
If gzip is on in your nginx config, check that gzip_types doesn’t include already-compressed formats. Compressing a zip or any binary download wastes CPU for no size benefit, sometimes it makes the file bigger:
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
Leave application/zip, application/octet-stream, and image formats out of that list entirely.
On the PHP side, if your download links run any permission check or download counter before the X-Accel-Redirect header fires, that’s still a PHP-FPM hit per download even with the redirect in place. Worth confirming OPcache is tuned for it, the defaults are conservative:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
If you deploy plugin updates through wp-admin rather than CI, keep validate_timestamps=1 with that revalidate_freq, it avoids stale bytecode after an update while still cutting filesystem checks under load.
Last thing worth considering for a downloads site specifically: if the files themselves are large or bandwidth heavy, moving them off the Droplet onto DigitalOcean Spaces with the CDN enabled offloads both the bandwidth and the CPU cost of serving them, WordPress just issues a redirect to the Spaces URL instead of an X-Accel-Redirect to local disk. One thing to know before doing that: if downloads need to stay gated behind login or permission checks, presigned Spaces URLs bypass the CDN and hit origin on every request, so that architecture only pays off for downloads that are effectively public once issued.
Hope that this helps!
I’d profile the server before upgrading. Check PHP-FPM slow logs, Redis cache hit rate, and MySQL performance to identify the real bottleneck. Also make sure OPcache is enabled and size based on available RAM, not guesswork. Often these optimizations reduce CPU spikes significantly before scaling becomes necessary.