Search code examples
phpvarnishvarnish-vcl

Purge all files under a directory with Varnish HTTP accelerator


Is it possible to purge all files underneath a specific directory using Varnish? How could you go about completing this in a PHP script?

For example, if a URL includes the path /product/a-specific-product/, is it also possible to purge files such as /product/a-specific-product/a-sub-page/?

I have the following functions that are used to purge a specific URL in Varnish 3 (part of class VarnishPurger():

public function executePurge()
{
    $purgeUrls = array_unique($this->purgeUrls);

    foreach($purgeUrls as $url)
    {
        $this->purgeUrl($url);
    }

    if (!empty($purgeUrls))
    {
        $this->purgeUrl(home_url());
    }        
}

protected function purgeUrl($url)
{
    $c = curl_init($url);
    curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'PURGE');
    curl_exec($c);
    curl_close($c);    
}

Solution

  • You can create a custom PURGE handler in Varnish to handle regexp purges using, for instance, ban_url().

    For instance in PHP when you want to purge add a custom HTTP header for Varnish to spot.

    curl_setopt($c, CURLOPT_HTTPHEADER, array('X-Purge-Regex-URL'));
    

    Then in vcl_recv() add

    if (req.http.X-Purge-Regex-URL) {
      if (!client.ip ~ purge) {
        error 405 "Not allowed.";
      }
      ban_url(req.url);
      error 200 "Banned URL";
    }
    

    Now when you issue a purge for /product/a-specific-product/ everything matching the regexp, including /product/a-specific-product/a-sub-page/ will be purged.

    Please note that the HTTP host is disregarded, so if you are running virtual hosts and want only specific sites to be purged, you need to use ban() instead with req.http.host and req.url parameters. Please let me know should you need this type of a solution instead.

    Also, as mentioned, the purge is a regexp purge, so purging /product will purge all URLs matching product.