[pmwiki-users] Extremely fast static page cache with nginx

Ed W lists at wildgooses.com
Mon Mar 16 07:51:32 CDT 2015

Hi, I have had some success using recent Nginx's feature to do fastcgi 
output caching. I don't have capacity to write up on the wiki neatly, 
but I wonder if someone would like to repro this and writeup?

Essentially recent Nginx has a feature to cache proxied fastcgi output. 
Actually it's had that feature for a long time, however, only recently 
it introduced "If-Modified-Since" support to the caching.  This means 
that if you have a working pmwiki which is setup to correctly use IMS, 
then you can trivially turn on nginx caching which captures the full 
rendered HTML and saves/serves it from disk automatically.  It will 
check upstream IMS on each page fetch, so updates will be immediately 
noticed (additionally you could play with the Expires header to prevent 
this check and get even more speed)

For me this brings page render time down from 300-600ms to 5-6ms (which 
is roughly my ping time to my server).

The rough overview of my setup is:

- I have my server definitions in /etc/nginx/vhost.d
- Various standard config definitions live in /etc/nginx, eg setup of 
ruby or php environments, standard SSL params, standard gzip params, etc.
- I include cache.conf into nginx.conf
- I have a vhost definition in vhost.d which sets up the server, logging 
details, etc and then includes std_pmwiki.conf to do the work
- Note my wiki php lives in $HTMLROOT/w/ there is no reason you couldn't 
put the files somewhere else, including in the root directory
- Be careful with nginx to avoid executing php code which can be 
uploaded by the user. I recommend specific location entries which 
redirect desired scripts to some virtual location. The virtual location 
redirects to execute the PHP environment. This is NOT how it's done 
below... This is an older config that I haven't updated yet.
- So in the location where we execute the PHP code it's relatively 
straightforward to turn on cgi caching. We must forcibly ignore the 
Cache-Control and Expires headers since they request no caching (Note, I 
disagree that the correct headers are returned by pmwiki?). Also we make 
some exceptions to bypass caching under certain circumstances, eg we 
only cache non logged in users, doing GET/HEAD requests
- Not shown here, but ideally we should examine the url parameters and 
consider not caching certain request types. However, this can probably 
be done more cleanly by being more selective about ignoring the 
Cache-Control headers from pmwiki and moving such logic upstream? (eg 
look at Cache-Control: no-store ?)

Nginx will automatically build an html store for you. Nginx must be 
compiled with the cache feature.  You can expire the cache in various 
ways, including "rm -rf".  Here I also set a reasonably short html cache 
expiry time (few days) to avoid very stale pages being delivered if I 
overlooked something.

I quite like this solution because it moves the intelligence upstream 
into pmwiki. Improvements in caching in pmwiki automatically flow down 
to us here.

Any comments? (Apologies for sketchy writeup and mishmash of tabs/spaces 
in the config below)

Ed W

# cat /etc/nginx/cache.conf

# Setup caching for pmwiki (and others?)

fastcgi_cache_path  /var/www/cache/fastcgi levels=1:2 keys_zone=fastcgi:8m max_size=100m inactive=600m;

fastcgi_temp_path /var/www/cache/tmp;

fastcgi_cache_key "$scheme$request_method$host$request_uri";


# cat /etc/nginx/std_pmwiki.conf

         rewrite ^/$ /w/pmwiki.php last;

         rewrite ^/sitemap.xml$ /w/pmwiki.php?action=sitemap last;

         location /w/pub/ {

                         # serve static files that exist without running other rewrite tests

                         if (-f $request_filename) {

                             expires  7d;




         location /w/uploads/ {

                         # serve static files that exist without running other rewrite tests

                         if (-f $request_filename) {

                             expires  2d;




        location / {

                         if (!-e $request_filename) {

                                 rewrite  ^/+([^\./]+(/[^\./]*)?)$ /w/pmwiki.php?n=$1 last;



         location ~ /w/pmwiki\.php$ {

             include /etc/nginx/fastcgi.conf;


             # caching

             set $no_cache 0;

             # Don't cache logged in users

             if ($http_cookie ~ (PHPSESSID*)) {

                 set $no_cache 1;


#            if ($query_string ~ "action=") {

#                set $no_cache 1;

#            }

             fastcgi_cache_bypass     $no_cache;

             fastcgi_no_cache         $no_cache;

             fastcgi_cache            fastcgi;

             fastcgi_cache_methods    GET HEAD;

             fastcgi_cache_valid      2880m;

             fastcgi_cache_revalidate on;

             fastcgi_ignore_headers   Cache-Control Expires;

             add_header               X-Cache-Status $upstream_cache_status;


         location /w/ {

                         # unless rewritten to the php script then you get a 403 Forbidden

             deny all;


More information about the pmwiki-users mailing list