We have been evaluating caching reverse proxy servers at work. We looked at
Nginx+memcached,
Squid, and
Varnish. Most recently,
we found that Nginx version 0.7 has
support
for caching static files using the proxy_cache directive in
the NginxHttpProxyModule.
This allows us to use Nginx as a caching proxy without having to handle the
complication (or flexibility depending on how you look at it) of setting and
invalidating the cache as with the Nginx+memcached setup.
Here are my notes for setting it up with an Apache+Wordpress backend.
Update 2010-01-05: Over a couple months, we switched to Nginx 0.8 and we made a few tweaks to our Nginx configuration. Here is our updated conf file: nginx_wordpress_100105.conf.
The version of Nginx in Ubuntu is an older version so we used a PPA created by Jeff Waugh: https://launchpad.net/~jdub/+archive/ppa. (He also has a development PPA which contains Nginx 0.8.)
deb http://ppa.launchpad.net/jdub/ppa/ubuntu hardy main deb-src http://ppa.launchpad.net/jdub/ppa/ubuntu hardy main
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E9EEF4A1
Alternively, if the keyserver is down, you can follow the instructions for copying the public key from http://forum.nginx.org/read.php?2,5177,11272.
apt-get update apt-get install nginx
nginx -V
nginx version: nginx/0.7.62 configure arguments: --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --with-debug --with-http_stub_status_module --with-http_flv_module --with-http_ssl_module --with-http_dav_module --with-http_gzip_static_module --with-ipv6 --with-http_realip_module --with-http_xslt_module --with-http_image_filter_module --with-sha1=/usr/include/openssl
Within the http {} block, add:
log_format cache '***$time_local '
'$upstream_cache_status '
'Cache-Control: $upstream_http_cache_control '
'Expires: $upstream_http_expires '
'"$request" ($status) '
'"$http_user_agent" ';
access_log /var/log/nginx/cache.log cache;
Within the http {} block, add:
include /etc/nginx/app-servers.include;
And /etc/nginx/app-servers.include looks like:
upstream backend {
ip_hash;
server 10.245.275.88:80;
server 10.292.150.34:80;
}
Within the http {} block, add:
proxy_cache_path /var/www/nginx_cache levels=1:2
keys_zone=one:10m;
inactive=7d max_size=200m;
proxy_temp_path /var/www/nginx_temp;
We added the username from the wordpress_logged_in_* cookie as part of the cache key so that different logged in users will get the appropriate page from the cache. However, our Wordpress configuration sends HTTP headers disabling the cache when a user is logged in so this is actually not used. But it does not hurt to include this, in case we change our Wordpress configuration in the future.
Within the server {} block, add:
location / {
# capture cookie for use in cache key
if ($http_cookie ~* "wordpress_logged_in_[^=]*=([^%]+)%7C") {
set $my_cookie $1;
}
proxy_pass http://backend;
proxy_cache one;
proxy_cache_key $scheme$proxy_host$uri$is_args$args$my_cookie;
proxy_cache_valid 200 302 304 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m;
}
If WordPress sends the appropriate HTTP Cache-Control headers, this step
is not necessary. But we have added it to be on the safe side.
Within the server {} block, add:
location /wp-admin { proxy_pass http://backend; }
location /wp-login.php { proxy_pass http://backend; }
The Nginx reverse proxy cache should work without modification to the Apache configuration. In our case, we had to disable WP Super Cache because we had been using that previously.
/etc/init.d/nginx restart
Check the /var/log/nginx/cache.log to see if everything is
working correctly. The log should diplay HIT, MISS,
and EXPIRED appropriately. If the log shows only misses, check
the Cache-Control and Expires HTTP headers that are sent from Apache+Wordpress.
Part of the WP Super Cache configuration included the following in the
.htaccess file. It had to be removed for Nginx cache the pages.
(In particular, the must-revalidate part had to be removed.)
Header set Cache-Control 'max-age=300, must-revalidate'
Hi,
I have googled a couple of days to find any info about configuring nginx+apache+wordpress with proxy cahce. It seems your post is the only one! Thank you for this work!
I have a gap in understanding how the nginx's proxy_cache actually works: does it cache only statics or apache genrated html?
Thank you in advance!
Hi Vitol, I'm glad you found the post-- hopefully it will be helpful to you. The Nginx forum also has a lot of information. Do a search for "proxy_cache" there.
To answer your question, Nginx can cache both static media files and apache generated html.
Hi Eliot,
How do you deal with cache purging? For example, if some user who is not logged in posted a comment, you need to invalidate the cached page. Or else, that user will get a cached version of a page without his own comment.
Oren
Hi Oren,
This is an issue that we faced. This Nginx module doesn't support purging the cache so we just have to wait the short time (10 minutes in our case) for the cached page to expire.
Regarding the comment pages, we actually added the comment author's name and email from the Wordpress cookie as part of the cache key so each person sees their own page. I added a link to our updated conf file at the top of the post.
Eliot
I'm Eliot and this is my notepad for programming topics such as Python, Django, Ubuntu, Emacs, etc... more »