Purging the nginx cache when users differ

A number of WordPress plugins for purging the nginx fastcgi cache rely on directly accessing the cache files in the file system. This works when nginx and PHP run as the same Linux / Unix user — but not when they have separate users.

The plugin Nginx Helper, among others, can purge individual cache files by nicely asking nginx to do it, through a plugin setting to use a Get request for purging. The URL that does it looks like this:


When we add, edit, or delete a post, Nginx Helper asks nginx to purge the cache for that post, the home / posts page, and any category and tag archives that might be affected. It works because nginx is deleting the cache files, not PHP. Here’s what the nginx configuration block looks like to support that; note that it’s restricted to the IP addresses of the web server, because we don’t want just anyone calling it!

location ~ ^/purge(/.*) {
	allow 555.1.1.1;
	deny all;
	include fastcgi_params;
	fastcgi_cache_purge cache_zone $scheme$request_method$host$1;

Nginx Helper also has a Purge Cache button on the WordPress toolbar, which will purge the whole cache — but it can only do it by directly accessing the cache files, so it fails when nginx and PHP run as different users. What we need is a way to ask nginx to do that bit for us too. And luckily, there is a way.

When we install nginx on Ubuntu or a derivative, one of the packages we can install is nginx-extras. Apart from the all important Cache Purge module which allows us to purge individual cache files, it also brings the Lua module for nginx. Lua is a lightweight programming language that allows us to write code within our nginx configuration. This is a very nifty thing, as it allows us to do things we’d normally need to do in PHP or another language outside of nginx. Like asking nginx to delete all of its cache files!

Update: it seems that Ubuntu 22 doesn’t include the Lua module in nginx-extras; see further down this article for how to do this with the Perl module that is still included in nginx-extras!

location /purge-all {
	allow 555.1.1.1;
	deny all;
	content_by_lua_block {
		os.execute("rm -rf /var/cache/nginx/*");

Now, we can purge the whole cache by asking nginx to /purge-all, and nginx can do it because it’s the owner of the files.


Of course, that call also has to come from inside the house website, so it’s best if we can hook it up to the Purge Cache in Nginx Helper. To do that, we need to intercept that button press in PHP, and handle it ourselves. And here’s how we do that.

 * override Purge All button for Nginx Helper plugin
 * this utilises some Lua code in the nginx config of this website
add_action('admin_bar_init', function() {
	$input  = $method === 'POST' ? INPUT_POST : INPUT_GET;
	$action = filter_input($input, 'nginx_helper_action', FILTER_SANITIZE_STRING);
	$mode   = filter_input($input, 'nginx_helper_urls', FILTER_SANITIZE_STRING);

	// only process if Purge All is requested from the WP admin
	if ($action === 'purge' && $mode === 'all' && is_admin()) {
		// verify request is from an authenticated admin
		if (!current_user_can('manage_options')) {
			wp_die('Sorry, you do not have the necessary privileges to purge the whole cache.');

		// ask nginx to purge all items from the cache
		// NB: this is a custom URI handled by Lua code in the nginx config


		$redirect_url = add_query_arg(['nginx_helper_action' => 'done']);
}, 9);

And job is done, from within WordPress, without having to drop to a command line to manually remove those cache files.

Update: since the Lua module is no longer included with nginx-extras on Ubuntu and derivatives (since Ubuntu 21 maybe, but certainly 22.10 doesn’t have it) here is how to do exactly the same thing with the Perl module for nginx. Thankfully, the Perl module is still included in nginx-extras!

First, we create our minimalist Perl module for executing the purge-all. Save this into /etc/nginx/lib/perl/purge_all.pm

package purge_all;

use nginx;

sub purge {
	system "rm -rf /var/cache/nginx/*";


Now we hook that into our site config. At the top, outside any server blocks, we tell nginx about our Perl module:

# enable Perl module for purge-all
perl_modules /etc/nginx/lib/perl;
perl_require purge_all.pm;

And inside the server block, we add our handler for the /purge-all path:

location /purge-all {
	allow 555.1.1.1;
	deny all;
	perl purge_all::purge;

And now, job is done twice — once in Lua, once in Perl. Cutting twice seems to be a thing in software development.