The RaspberryPi can be a cheap webserver and did prove powerful enough to serve mainly static content even over a home broadband connection. But what happens when you use the RaspberryPi to host your Wordpress blog? The answer is: it performs well but only with full caching.

RaspberryPi with Nginx and Wordpress

Wordpress is mainly developed with Apache in mind but fortunately wordpress also runs on nginx out of the box. That's the good news. The bad news is that the performance of the RaspberryPi is horrible!

average page load time in ms of a standard wordpress installation hosted on a RaspberryPi without any caching.

A standard wordpress installation clocks around 3 seconds page load time on a RaspberryPi running in 1GHz turbo mode. This is already terrible without any significant traffic on your blog. Obviously, we have get all the caching working!

Caching for Wordpress on Nginx

Enabling caching isn't absolutely straight forward on a Nginx server. It requires some further work setting up the nginx.conf file for example. Most of the necessary bits come from codex

Warning! Please proceed only if you know what you are doing! This tutorial comes with a overall exclusion of liability!

  1. log into your wordpress and download the two plugins Nginx Helper and WP Super Cache. Don't forget to activate the plugins.
  2. Still in Wordpress activate Permalinks in Settings->Permalinks and set them to Post name
  3. enable caching in Settings->WP Super Cache
  4. Nginx comes with build in support for caching! To enable the Nginx cache open your server configuration file nginx.conf and add the following to the http section of the file
    fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:50m inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    
    and add a cache check into the server block for your wordpress blog as follows
    #fastcgi_cache start
    set $no_cache 0;
    
    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
            set $no_cache 1;
    }   
    if ($query_string != "") {
            set $no_cache 1;
    }   
    
    # 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 $no_cache 1;
    }   
    
    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
            set $no_cache 1;
    }
    
  5. Next we need to add some bits to make the WP Super Cache working. Please add this to your server block:
    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';
    }
    
  6. Finally the general setup for Wordpress within the server block
    # Add trailing slash to */wp-admin requests.
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;
    
    # Directives to send expires headers and turn off 404 error logging.
    location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
           access_log off; log_not_found off; expires max;
    }
    
    location ~ .php$ {
             try_files $uri =404; 
             include fastcgi_params;
             fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
    
             fastcgi_cache_bypass $no_cache;
             fastcgi_no_cache $no_cache;
    
             fastcgi_cache WORDPRESS;
             fastcgi_cache_valid  60m;
     }
    
    location / {
            try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php?$args /index.php?$uri$args;
    }    
    
  7. When you have your wordpress installation in a sub-directory like /blog/ you have to add one more location block to your server block as follows.
    location /blog/ {
            try_files /blog/wp-content/cache/supercache/$http_host/$cache_uri/index.html /blog/$uri /blog/$uri/ /blog/index.php?$args /blog/index.php?$uri$args;
    }  
    

This is already all what's needed to get the full caching for Wordpress running with Nginx. And the results speak for themselves:

average page load time in ms of wordpress on a RaspberryPi without any caching vs with caching.

The caching reduces the page load time to around 200ms which is now more than acceptable. Finally, how does heavy traffic influence the performance? I did a load test with up to 50 concurrent users and the page load time is pretty much constant under load. Most of the fluctuation should come from the Wifi connection.

The page load time in ms with x concurrent requests.