WordPress in 1 ms: cache, OPcache and gzip on a small VPS
WordPress is not slow by itself. It is slow when every visit makes PHP build the page again, with dozens of database queries. On a small VPS you notice that right away. These are the four settings we put on every WordPress server of ours, and what they really gained us. The commands are for Debian/Ubuntu with nginx and PHP-FPM.
What we measured
A test with a new WordPress on the Start plan (Debian 12, PHP 8.2), home page:
- PHP builds the page: about 47 ms on the server itself
- Ready page from the cache: about 1 ms
- From outside, over the internet, no cache: the first byte arrives after about 100 ms
- From outside, with cache: about 55 ms. The rest is the network path itself.
- HTML size: 12 KB compressed instead of 70 KB
Page cache
The biggest win. The plugin saves the finished page as a file, and the next visitor gets it directly, with no PHP and no database. We use Cache Enabler: free, no settings needed, it clears the cache by itself when you edit or publish something, and it does not cache for logged-in users (so /wp-admin/ always shows the current state).
Code: Select all
# with WP-CLI, from the site folder
wp plugin install cache-enabler --activate
OPcache
PHP compiles its code on every request. OPcache keeps the compiled code in memory. It is usually installed already, but with too little memory for a big project like WordPress.
Code: Select all
php -v # check the version, e.g. 8.2
sudo apt install -y php8.2-opcache
echo "opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2" | sudo tee /etc/php/8.2/fpm/conf.d/90-opcache.ini
sudo systemctl restart php8.2-fpm
php-fpm8.2 -m | grep -i opcache # should say: Zend OPcacherevalidate_freq = 2 means PHP checks for changed files every 2 seconds. When you upload a new plugin version, it shows up almost at once.
gzip and caching for CSS, JS and images
By default nginx on Debian compresses only HTML. CSS and JavaScript go out uncompressed, and the browser downloads them again on every visit. In the site's server { } block:
Code: Select all
gzip on;
gzip_proxied any;
gzip_vary on;
gzip_types text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml;
location ~* \.(?:css|js|mjs|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm)$ {
expires 30d;
access_log off;
try_files $uri =404;
}Code: Select all
sudo nginx -t && sudo systemctl reload nginx?ver= to its files. A new version has a new address, so the browser downloads it again.location ~ /\.), put the static-files block after it.
wp-cron from the system, not from visitors
WordPress runs its scheduled tasks (scheduled posts, updates, backup plugins) during a visit. Some visitor waits. It is better to run them every 5 minutes from the system. In wp-config.php, before the line "That's all, stop editing":
Code: Select all
define('DISABLE_WP_CRON', true);sudo crontab -u www-data -e):
Code: Select all
*/5 * * * * wp --path=/var/www/wordpress cron event run --due-now --quietcurl -s https://your-site/wp-cron.php >/dev/null.
How to check it yourself
Code: Select all
curl -s -o /dev/null -H "Accept: text/html" -w "first byte: %{time_starttransfer}s\n" https://your-site/-H "Accept: text/html" matters: Cache Enabler serves the cached page only when the request asks for HTML. A browser does that by itself; curl without it does not, and will show you the slow time.
With us it is on from the start
When you order a VPS with WordPress, everything above is already done: Cache Enabler, OPcache, gzip and caching for static files, wp-cron from the system. The site also goes through Cloudflare, which keeps CSS, JS and images close to the visitor. You only write the content.Questions, or your own measurements? Post them here in the topic