Search code examples
regexvarnishvcl

Varnish 4.0 multiple matches


I need to invalidate cache in Varnish for multiple specific values of one parameter simultaneously. Now the code makes calls following this pattern:

varnish_host/path?.*parameter=1
varnish_host/path?.*parameter=2
varnish_host/path?.*parameter=3
varnish_host/path?.*parameter=4

And following a documentation of Varnish 2.0 found here https://kly.no/varnish/regex.txt I found this rule for multiple matching

Multiple matches
    req.url ~ "\.(jpg|jpeg|css|js)$"
    True if req.url ends with either "jpg", "jpeg", "css" or "js".

So I changed my code to adapt it in the following way

varnish_host/path?.*parameter=(1|2|3|4)$

But it does not clean the cache as expected, even if it returns a status 200.

Is there in Varnish 4.0 a way to do this multiple match in a parameter? If so, is there a limit in the number of variations that we should have into account?


Solution

  • Varnish doesn't offer an out-of-the-box HTTP-based invalidation mechanism.

    What you can do is issue bans using varnishadm. This will allow you to setup regex patterns that match multiple objects.

    Varnishadm ban example

    Here's such an example, where we will invalidate each PNG file in the cache for the example.com hostname:

    varnishadm ban req.http.host == example.com '&&' req.url '~' '\\.png$'
    

    HTTP-based banning & purging

    varnishadm works fine, but isn't that easy to integrate into your logic. If you want to invalidate objects from the cache via purge or ban, you need to write some VCL.

    Here's a VCL snippet that will facilitate HTTP-based invalidation:

    vcl 4.0;
    
    acl purge {
        "localhost";
        "192.168.55.0"/24;
    }
    
    sub vcl_recv {
        if (req.method == "PURGE") {
            if (!client.ip ~ purge) {
                return(synth(405, "Not allowed."));
            }
            if (!req.http.ban-url) {
                return(purge);
            }
            ban("obj.http.x-host == " + req.http.host + " && obj.http.x-url ~ " + req.http.ban-url);
            return(synth(200, "Ban added"));
        }
    }
    
    sub vcl_backend_response {
        set beresp.http.x-url = bereq.url;
        set beresp.http.x-host = bereq.http.host;
    }
    
    sub vcl_deliver {
        unset resp.http.x-url;
        unset resp.http.x-host;
    }
    

    Important: you need to adjust the values of the ACL, which will prohibit unauthorized access to the invalidation interface. You can use IP addresses, IP ranges, and hostnames to limit access.

    Here's how we perform the same PNG invalidation via HTTP:

    curl -XPURGE -H"ban-url: '\.png$'" http://example.com/
    

    You can also just invalidate a single URL:

    curl -XPURGE http://example.com/my-page
    

    Because the example above doesn't contain an ban-url request header, only the exact URL is invalidated, instead of a pattern begin matched.