Varnish Tutorial Part 2: Clearing Varnish Cache

This is the second part to my Varnish tutorial series. In this article we'll take a look at clearing the cache.

More In This Series

Review

In the previous tutorial, we ended up with the following default.vcl:

default.vcl

vcl 4.1;

backend default {
  .host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com:80";
}

sub vcl_recv {
  set req.http.host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com";
}

After starting Varnish, we can then verify it is working with curl:

bash

curl -v http://localhost:8080/

The output should look something like this:

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html
< Server: AmazonS3
< Content-Length: 1875
< X-Varnish: 9 3
< Age: 11
< Via: 1.1 varnish (Varnish/7.0)
< Accept-Ranges: bytes
< Connection: keep-alive
<
[HTML redacted]

Clearing Pages From Varnish Cache

With our current configuration, we have to completely restart Varnish in order to clear the cache. Let's change that by ammending default.vcl:

default.vcl

vcl 4.1;

backend default {
  .host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com:80";
}

sub vcl_recv {
  set req.http.host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com";

  if (req.method == "PURGE") {
    return (purge);
  }
}

As you can see, we've added a conditional to sub vcl_recv. This checks if the HTTP method is PURGE, and if so it removes the requested page from cache. Restart Varnish, then test with curl:

bash

curl -vX PURGE http://localhost:8080/

The output should show header HTTP/1.1 200 Purged:

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PURGE / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 Purged
< Server: Varnish
< X-Varnish: 32772
< Content-Type: text/html; charset=utf-8
< Retry-After: 5
< Content-Length: 240
< Connection: keep-alive
<
[HTML redacted]

The next GET request should return an Age: 0 header to indicate it is not a cached response.

This purges the cache for the requested page. So in order to clear http://localhost:8080/foo/ for example you would run curl -vX PURGE http://localhost:8080/foo/.

Completely Clearing Varinsh Cache

The above is great for selectively clearing pages from Varnish, but what if we want to clear all pages? Let's revisit default.vcl:

default.vcl

vcl 4.1;

backend default {
  .host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com:80";
}

sub vcl_recv {
  set req.http.host = "beakerstudio-splash.s3-website.us-east-2.amazonaws.com";

  if (req.method == "PURGE") {
    ban("req.http.host ~ .*");
    return (synth(200, "Full cache cleared"));
  }
}

Here we have replaced return (purge); with a call to ban with a pattern that matches all pages on the configured host, and then send a custom HTTP 200 response.

Once again we use curl -vX PURGE http://localhost:8080/ to clear the cache. This time tthe output should show header HTTP/1.1 200 Full cache cleared:

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PURGE / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 Full cache cleared
< Server: Varnish
< X-Varnish: 32772
< Content-Type: text/html; charset=utf-8
< Retry-After: 5
< Content-Length: 276
< Connection: keep-alive
<
[HTML redacted]

Next Steps

In this tutorial we looked at two different ways to clear Varnish cache. There's one major omission you might have noticed, which is that we don't authenticate PURGE requests. This means anyone may clear our cache, which could lead to performance issues and DoS attacks! In the next article we will cover securing Varnish against PURGE attacks.

Published: