I had the good opportunity of ending up on Jim Westgren’s article about using Redis as a front end cache and it didn’t take long for me to try it on one of my virtual boxes. The results were unbelievable, pages that were taking about 0.2 to 1.2 seconds were now loading at 0.0025 second on average.
Unfortunately, Jim is a bit busy showing us how he configured his server to run on nginx + php-fpm + apc + cloudflare + redis. So in doing my share to make (a part of) the web faster and better for everyone here’s an install guide to get you started.
What You Need
A virtual private server (VPS), this unfortunately is required. If you are in a shared hosting environment, sorry but this isn’t for you. If you want to jump in managing your own VPS, I highly recommend DigitalOcean, cheapest and fastest that I’ve known so far, the one I currently use for all my sites.
The following applications, nginx, php-fpm, redis and predis, a flexible php client library for redis.
Finally, at least a very basic knowledge in using linux based systems. I prefer using CentOS and the server that this blog is on is using this distro.
Setting up Redis
If you’ve got all three covered, let’s get started. I’m too lazy to write a nginx + php-fpm installation guide now but you can refer to this article to setup the necessary applications on your vps. Install nginx and php-fpm, make sure it’s configured properly to run WordPress.
Install redis on your server, here’s a clean and easy to follow guide for installing redis on CentOS. Make sure Redis is running on your server before continuing.
Setup a WordPress blog on your vps. While I don’t have a good guide yet based on my setup, I recommend you read this guide to get you started.
Installing WP Index Redis
Please download wp-index-redis.php, you’ll need this to interface WP with Redis.
I really don’t have a name for this script but, I’ll just call it it WP Index Redis for now. I’ve made a lot of changes to the script that Jim originally created but here are the main difference:
- Pages are not cached when you are logged in.
- Cached pages do not expire not unless explicitly deleted or reset (deleting the entire domain cache).
- Appending a ?c=y (e.g. domain.com/?c=y) to a url deletes the entire cache of the domain. Only works when you are logged in.
- Appending a ?r=y to a url deletes the cache of that url.
- Refreshing (F5) a page deletes the cache of that page.
- Script still works even if allow_fopen is disabled in php.
- Submitting a comment deletes the cache of that page.
- Includes a debug mode, stats are displayed at the bottom most part after </html>. Won’t be deleted by CloudFlare.
Like always, use this at your own risk. Be comforted though that I use this myself on this very blog. So on to installing the redis cache interface:
Edit wp-index-redis.php and change some variables where appropriate. The default should work out of the box, but if you are using CloudFlare set $cf = 1, and if you’d like to see some cache generation times set $debug = 1. Otherwise leave everything as it is.
Upload wp-index-redis.php on your WP blog. Make sure you upload this where your main WordPress index.php resides.
Do the same for predis.php.
Rename the WordPress index.php to _index.php or any name that will indicate that this is the original index.php.
Rename wp-index-redis.php to index.php. That’s it you are all set.
Open your browser and access your site, if you’ve enabled debug, you should see some page execution status and figures at the bottom most part of each WordPress page.
For the curious, this blog is on CentOS with nginx + php-fpm + mysql + redis. I didn’t bother (for now) to install apc or xcache because I believe in the mantra, less is more. In the very near future I should be able to publish a guide on how I’ve setup my vps.
If nothing broke on your site, you can breathe now, congratulate yourself and let your neighbor know that your level of geek has just plus-oned (+1) today. ^_^



{ 27 comments… read them below or add one }
just curios if this is strictly nginx only or can I use it for apache too?
saw the original article where you got the original script from, there were a few suggestions to turn this into a plugin or an object cache plugin, any chance that is going to happen?
I tried this on Apache and am not gettign anywhere. is this nginx only?
see errors:
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: PHP Fatal error: Uncaught exception ‘Predis\\ServerException’ with message ‘unknown command ‘HEXISTS” in /var/www/clients/client1/web3/web/predis.php:562
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: Stack trace:
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #0 /var/www/clients/client1/web3/web/predis.php(689): Predis\\ResponseErrorHandler->handle(Object(Predis\\Connection), ‘ERR unknown com…’)
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #1 /var/www/clients/client1/web3/web/predis.php(1374): Predis\\ResponseReader->read(Object(Predis\\Connection))
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #2 /var/www/clients/client1/web3/web/predis.php(1383): Predis\\Connection->readResponse(Object(Predis\\Commands\\HashExists))
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #3 /var/www/clients/client1/web3/web/predis.php(202): Predis\\Connection->executeCommand(Object(Predis\\Commands\\HashExists))
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #4 /var/www/clients/client1/web3/web/index.php(66): Predis\\Client->__call(‘hexists’, Array)
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #5 /var/www/clients/client1/web3/web/index.php(66): Predis\\Client->hexists(‘efa3ef8516319ee…’, ’2de6e35e8cc7eb6…’)
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: #6 {main}
[Thu Oct 25 16:40:36 2012] [warn] [client 108.162.222.170] mod_fcgid: stderr: thrown in /var/www/clients/client1/web3/web/predis.php on line 562
Hi Ovidiu,
Yes this setup is currently for nginx. If you’ve setup redis properly though, it should run fine with no problems with apache (theoretically) since redis runs as a separate process.
As far as making this into a plugin, not sure yet as of this time. As far as my opinion is concerned I think this is the better implementation so far because no process is touched in WordPress once the redis cache is hit.
I’ll find a better means to implement this though soon as I have time.
With the errors you are encountering, I suggest you check your redis version and make sure you install the latest stable release. The messages you are getting suggests that the called function doesn’t exist.
Hello. I’m using Nginx with fastcgi_cache like in this tutorial : http://rtcamp.com/tutorials/wordpress-nginx-fastcgi-cache-purge-conditional/ Is your method compatble with this one, or is it replacement of such a method ? I would be glad if you can answer this, I’m just discovering the capabilities of Redis (I’m using it with etherpad-lite and haste-server for the moment, replacing sqlite for the first one and memcache for the second) and I want to make more use of it. Thank you for this post, I bookmarked it.
Hi PostBlue,
Technically yes, but there’s nothing to gain from it. It’s a different approach and using redis would be redundant as both cache hits are called directly from memory. Theoretically, the approach you referred should be faster because pages are served directly by nginx and doesn’t even hit the wordpress layer. I’m using redis out of curiosity and because the fastcgi_cache_purge module isn’t installed on my vps.
Awesome post, Jeedo!
How to configure predis.php to listen to the Redis socket (not the port #) and avoid the TCP overhead? I guess that could improve the performance a bit further.
Hi Resende,
Thanks for the suggestion, I’ll look it up and see if I can improve this further. Been busy with work lately but I really want to make an update on this redis wordpress cache.
Thanks, Jeedo.
Maybe replacing DEFAULT_HOST = ’127.0.0.1′ for the absolute unix path of the socket would do the trick, but I’m not that sure.
Something I just noticed is that the cache is not serving CDN files (CloudFront in my case). It grabs them directly from my server. Is there any way to bypass that?
I’m getting the following errors after doing all the steps:
Warning: Unexpected character in input: ‘\’ (ASCII=92) state=1 in /home/wwwroot/domain.com/index.php on line 50
Parse error: syntax error, unexpected T_STRING in /home/wwwroot/domain.com/index.php on line 50
which corresponds to this line:
$redis = new Predis\Client(”);
Any ideas of what the problem might be?
Hi Albi,
Please check your PHP version, I’m running version 5.4, if you are running anything less than 5.3, you might bump into problems. Check as well if you haven’t changed anything (after the variables) in the file by accident. It would also help if you let me know specifics about your setup like the OS, nginx version, redis version, etc.
Hi Resende,
Haven’t tried using unix sockets yet with redis probably will in the near future when I try out different configurations with nginx. I’m not sure how CloudFront works but I currently use CloudFlare, and it works seamlessly with my current setup. With your current setup, it should work theoretically though because what redis simply does is serve a static (cached) page from a server’s memory.
Hi,
Very interesting. I didn’t know much ’bout Redis prior to this.
I’ll give it a try later in the day (I will test connecting via unix socket, too).
Thanks.
-k0nsl
Hi k0nsl,
Thanks for dropping by, please let us know how it goes on your end. I hope your redis adventure will turn out without a hitch.
This solution works great except on ajax-submitted form (Contact Form 7). With redis caching (no W3TC or Varnish) the form won’t submit, it just spins and spins but never submits. Any ideas?
Hi afk4life,
Kindly mail me the URL where you installed Contact Form 7. As far as my experience goes as long as all the ajax and javascript libraries have been loaded, there shouldn’t be any conflict with redis since it’s just a front-end cache.
Hi great tutorial
I’ve just had my hosting install this for me, and it is coming up with a few errors.
First off i have a WP Multisite installation and was wondering if this works on my install
Thanks
Hi Safia,
It would help if you let us know what the errors are. We might find a fix for it.
After looking at some of the GET/SAVE functions of PHP Cache Lite, it looks simular to what the redis script does. https://pear.php.net/package/Cache_Lite/docs
Do you think that using Cache_Lite to checking/serving cache could be possible without the need for a 3rd party engine like redis, or an existing plugin like W3 Total Cache? Would there be any benefit to using PHP itself for caching?
Thanks,
Chris
Hi Chris,
Sorry not very familiar with cache_lite, I’d say because of the similarity, you just choose one or the other depending on which one you prefer and the way your server is setup. I use redis because it’s fast (memory store no disk read/writes) and I don’t need to add any third party plugin on my current WordPress install.
Hi,
I have the same problem as afk4life. how did you fixed it?
url: 1chatroom.ir/email/
Hi Pooya,
Unfortunately this redis cache won’t work with any plugin that alters content on the fly. I’ll try to find a work-around this one but I don’t think I’ll be doing that soon.
Hi Jeedo,
did you ever tried this installation with a VPS and a Multisite Installation or more than one site running on the server?
Hi Franky,
Unfortunately I haven’t tried it with wpmu yet. Just on a VPS with a single site wordpress install. I have two sites specifically on redis on a single VPS.
Hey there, what do I need to change on the redis files if REDIS is running on a multi server configuration? We have 2 front end servers, 1 db server, 1 NFS server for the content and a load balancer.
Can we use
$redis = new Predis\Client(array(
‘scheme’ => ‘tcp’,
‘host’ => ’10.0.0.1′,
‘port’ => 6379,
));
to load specific server where REDIS works?
Hi nicholas,
I’m no redis expert, what I can suggest is emulate a particular scenario and see if it works. I’ve always went to the trial and error route whenever I need to prove if a solution is viable.
Hi nicholas,
Not sure what your particular purpose is for running redis, but I suggest you read the documentation: http://redis.io/documentation, as I’m no redis expert unfortunately.