Search form

WordPress: Optimizing Nginx and WP Super Cache

Today we're going to compare the performance of a WordPress site before and after we install and optimize the WP Super Cache plugin.

We're running Ubuntu 16.04 Server, Nginx 1.10, PHP 7 with the Zend OPcache, MariaDB, and WordPress 4.6 with a few other plugins (Akismet, Jetpack, Yoast SEO, and Google Analytics). The system itself is a humble virtual server with 1 "core", 2 GB RAM, and SSD storage, costing $10/month.

To perform our testing, we're going to use the ApacheBench utility, simulating 5,000 requests with 5 concurrent connections. It's probably worth noting here that ApacheBench struggles to simulate realistic traffic patterns, so I wouldn't rely on it alone for load testing. If you're serious about trying to kill your web server, consider something like httperf or Siege.

Our WP Super Cache Optimizations

Here's our Nginx server block, with the Super Cache optimizations:

server {
        listen 80;
        listen [::]:80;

        server_name mywebserver.com www.mywebserver.com;

        error_log /var/log/nginx/mywebserver_error.log;
        access_log /var/log/nginx/mywebserver_access.log;

        root /var/www/mywebserver.com;
        index index.php index.html;

        ## Start WP Super Cache Configuration
        set $cache_uri $request_uri;

        # POST requests and urls with a query string should always go to PHP
        if ($request_method = POST) {
                set $cache_uri 'null cache';
        }

        if ($query_string) {
                set $cache_uri 'null cache';
        }

        # Don't cache uris containing the following segments
        if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-
        .*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.
        xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
                set $cache_uri 'null cache';
        }

        # Don't use the cache for logged in users or recent commenters
        if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
                set $cache_uri 'null cache';
        }

        # Use cached or actual file if they exist, otherwise pass request to WordPress
        # try_files won't find 'null cache' URLs
        location / {
                try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php?q=uri&$args;
        }

        ## End WP Super Cache configuration
 
        # Pass PHP scripts to FastCGI server listening on Unix socket
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

        # Caching of media: images, icons, video, audio, HTC
        location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff|woff2)$ {
                expires 2M;
                add_header Cache-Control "max-age=120, public";
        }

        # CSS and JavaScript
        location ~* \.(?:css|js)$ {
                expires 7d;
                add_header Cache-Control "max-age=604800, public";
        }
}

Benchmarking

First, we'll benchmark WordPress without WP Super Cache or any Nginx optimizations:

root@ubuntu:/# ab -c 5 -n 5000 http://www.mywebsite.com/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Server Software:        nginx/1.10.0
Server Hostname:        www.mywebsite.com
Server Port:            80

Document Path:          /
Document Length:        121787 bytes

Concurrency Level:      5
Time taken for tests:   353.619 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      610035000 bytes
HTML transferred:       608935000 bytes
Requests per second:    14.14 [#/sec] (mean)
Time per request:       353.619 [ms] (mean)
Time per request:       70.724 [ms] (mean, across all concurrent requests)
Transfer rate:          1684.69 [Kbytes/sec] received

Now let's install WP Super Cache and enable it with all recommended settings in the WP Dashboard:

root@ubuntu:/# ab -c 5 -n 5000 http://www.mywebsite.com/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Server Software:        nginx/1.10.0
Server Hostname:        www.mywebsite.com
Server Port:            80

Document Path:          /
Document Length:        121959 bytes

Concurrency Level:      5
Time taken for tests:   8.567 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      611489685 bytes
HTML transferred:       609795000 bytes
Requests per second:    583.65 [#/sec] (mean)
Time per request:       8.567 [ms] (mean)
Time per request:       1.713 [ms] (mean, across all concurrent requests)
Transfer rate:          69706.64 [Kbytes/sec] received

Better, but let's implement our optimized Nginx server block:

# ab -c 5 -n 5000 http://www.mywebsite.com/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Server Software:        nginx/1.10.0
Server Hostname:        www.mywebsite.com
Server Port:            80

Document Path:          /
Document Length:        121959 bytes

Concurrency Level:      5
Time taken for tests:   1.361 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      611030000 bytes
HTML transferred:       609795000 bytes
Requests per second:    3672.68 [#/sec] (mean)
Time per request:       1.361 [ms] (mean)
Time per request:       0.272 [ms] (mean, across all concurrent requests)
Transfer rate:          438303.80 [Kbytes/sec] received

With a few simple changes, we've taken our WordPress site from handling 14 requests/second to 3,600+. Imagine what you could do on some real server hardware, or if you added Varnish, Memcached or Redis.

Categories: