Search

What's new in Varnish 6?

What’s new in Varnish 6?

Varnish 6 is not a snapshot, and it doesn’t represent a single release: it’s the major version that groups a set of releases.

These are the seven Varnish versions that have been released so far:

  • Varnish 6.0 (released March 15th 2018)
  • Varnish 6.1 (released September 17th 2018)
  • Varnish 6.2 (released March 15th 2019)
  • Varnish 6.3 (released September 17th 2019)
  • Varnish 6.4 (released March 16th 2020)
  • Varnish 6.5 (released September 15th 2020)
  • Varnish 6.6 (released March 15th 2021)

Because Varnish is on a six-month release schedule, the minor versions go up quite quickly.

That doesn’t mean every release adds a lot of functionality. They happen on a regular basis, and when there’s something new, it’s added. Sometimes you end up with feature-heavy releases, sometimes there isn’t a lot to talk about.

There are also occasional maintenance releases. These aren’t really scheduled: they just happen when they happen, and they increase the patch version, e.g. Varnish 6.0.3. These maintenance releases contain bugfixes, enhancements, and sometimes even security fixes.

But in order to answer the question, and to tell you what’s new in Varnish 6, we need to look at the individual minor versions.

What’s new in Varnish 6.0?

Varnish 6.0 isn’t all that feature heavy. The new major version is primarily justified by the work that was done under the hood.

However, there are two features that are quite impactful:

  • Varnish 6.0 supports the use of UNIX domain sockets (UDS).
  • HTTP/2 support that was an experimental feature of Varnish 5 is now considered stable.

UNIX domain sockets (UDS)

Varnish is a proxy and a cache, but it is often more correct to think of it as a component in an HTTP-based application or application stack, where HTTP is the main communication protocol. Usually, the HTTP calls are made over TCP/IP, where the peer can be very close or somewhere across the globe.

But these services aren’t always located on different servers, so there isn’t always a need for a protocol that can route traffic over the network. TCP/IP is complex, and relatively speaking, there can be a significant overhead and latency when using it, even within the same server.

When the web server is hosted on the same physical machine, you can communicate over UDS instead of TCP/IP. The same applies when you terminate TLS on the same machine: the connection between the TLS terminator and Varnish can be made over UDS.

So instead of connecting to the web server using the following backend definition:

vcl 4.0;

backend default {
    .host = "localhost";
    .port = "8080";
}

you can remove TCP/IP from the equation and use the .path attribute to connect to the web server over UDS:

vcl 4.1;

backend default {
	.path = "/var/run/webserver.sock";
}

It’s also possible to listen for incoming Varnish connections over UDS by configuring the -a runtime option accordingly:

varnishd -a /var/run/varnish/varnish.sock,PROXY,user=vcache,group=varnish,mode=660

UDS support introduced a couple of new VCL variables:

  • local.endpoint: the address of the -a socket the session was accepted on
  • local.socket: the name of the -a socket the session was accepted on

These variables and the new .path attribute aren’t available in Varnish versions older than 6.0, so that forced a new VCL version.

When using UDS features in VCL, you have to make sure the VCL file starts with vcl 4.1;.

HTTP/2 support considered stable

There is not a whole lot to say about HTTP/2 support. Yes, it’s stable now, and there are a few new VCL variables related to this feature:

  • req.proto
  • bereq.proto
  • beresp.proto
  • resp.proto

These variables all expose the HTTP protocol version that is used for the request or response. These are either HTTP/1.1 or HTTP/2.0.

Using these variables in your VCL file also requires the file to start with vcl 4.1;.

At the moment, Varnish does not support HTTP/2 on the backend side, but the variables bereq.proto and beresp.proto are reserved for future versions of Varnish, which might support more protocols than HTTP/1.1 and HTTP/1.0.

Other features in Varnish 6.0

The shard director that is part of vmod_directors received lots of improvements.

vmod_unix was also added to retrieve the group id (GID), the user id (UID), the group name, and the user name of incoming connections over UDS.

vmod_proxy is a useful addition for users who terminate TLS and connect the TLS proxy to Varnish using the PROXY protocol. This VMOD has the ability to retrieve TLS information from the PROXY protocol. Most importantly whether or not the initial connection from the client was made using TLS.

Varnish 6.0 re-introduced a couple of removed VCL variables:

  • req.ttl: upper limit on the object age for cache lookups to return hit
  • req.grace: upper limit on the object grace

These variables are used to limit the time that objects are served from cache. Here’s an example of how they can be used:

vcl 4.1;
import std;

sub vcl_recv {
	if (std.healthy(req.backend_hint)) {
		set req.ttl = 1m;
		set req.grace = 10s;
	}
}

sub vcl_backend_response {
	set beresp.ttl = 1h;
	set beresp.grace = 10m;
}

Even though the time to live (TTL) is explicitly set to one hour in vcl_backend_response, setting req.ttl and req.grace will limit the effective TTL and grace for the current transaction. In other words, when the backend is healthy, Varnish will only serve objects for one minute with a ten-second grace. If it turns out that the backend is not healthy, the original TTL and grace values will be used.

More information about TTL and grace can be found in the next chapter.

Another feature worth mentioning is std.fnmatch, which is part of the standard VMOD (vmod_std). This function will perform shell-style pattern matching on a string, whereas PCRE-style pattern matching is otherwise used in Varnish.

What’s new in Varnish 6.1?

Varnish 6.1 is a periodic release. It’s one of those releases when the release date is due, but apart from bugfixes and enhancements, there’s nothing much more to say.

If you really care about the internals, you can always have a look at the most recent version of the changelog.

What’s new in Varnish 6.2?

Varnish 6.2 introduced two new variables that allow you to check if a request will bypass the regular caching flow, and immediately fetch the data from the backend. This happens when the corresponding backend response is marked as hit-for-miss or hit-for-pass. The respective variables are req.is_hitmiss and req.is_hitpass.

There was also an adjustment in the flow of Varnish’s finite state machine, which involved return(miss) being removed from vcl_hit{}. There are other ways to still trigger a miss, even when a hit took place, but it is no longer deemed a common scenario.

A couple of new type conversion functions were added to vmod_std.

A new lookup function was added to vmod_directors to look up individual backends by name.

The varnishadm command line tool can now return output in JSON format thanks to the -j option.

And logging programs like varnishlog and varnishncsa will perform better due to internal enhancements and the introduction of the -R rate-limiting option.

And as always: this version of Varnish features a number of bugfixes and enhancements.

What’s new in Varnish 6.3?

Explicitly trigger vcl_backend_error

Varnish 6.3 allows you to explicitly return an error from vcl_backend_fetch and vcl_backend_response. This triggers the vcl_backend_error state and can be achieved using either of the statements below:

return (error);
return (error(503));
return (error(503, "Service Unavailable"));

This is the erroneous equivalent of return (synth(200,"OK"));

VMOD import changes

In Varnish 6.3 it is now possible to import a VMOD multiple times. It’s also possible to run them under a different name, as illustrated below:

vcl 4.1;
import directors as dir;

sub vcl_init {
    new rr = dir.round_robin();
}

Behavior change in auto VCL temperature state

When loading multiple VCL files using varnishadm, the behavior of the auto state with regard to the VCL temperature has changed: in previous releases, the VCLs could cool down and would remain cold. As of Varnish 6.3 it works in both directions, and these VCLs can automatically warm up again when required.

std.ip() accepts optional port argument

The std.ip() function now accepts an optional port argument that overrides the default port value when it is called through std.port(). The default value is 80.

This is the new definition of std.ip():

IP ip(STRING s, [IP fallback], BOOL resolve=1, [STRING p])

Querying changes in VSL tools

VSL tools like varnishlog and varnishncsa have the ability to filter output based on VSL queries using the -q option.

Prior to Varnish 6.3, a new line in a -q statement was merely used as a token separator. As of Varnish 6.3, every new line in a -q statement is treated as a new query. Unless specified otherwise, the statements are joined with the or operator.

Here’s an example:

varnishlog -q "
    BerespStatus < 400
    ReqUrl eq '/'
"

Prior to Varnish 6.3, the use of multiple -q options would result in the last query being selected. As of Varnish 6.3, multiple queries will be joined with the or operator, as illustrated below:

varnishlog -q "BerespStatus < 400" -q "ReqUrl eq '/'"

The uppercase -Q is now available and reads stored VSL queries from a file. The -Q option can also be used multiple times, which just adds queries with the or operator to any query specified by either -q or -Q.

Here’s an example:

varnishlog -Q query1.vsl -Q query2.vsl

And finally the varnishncsa program can take an -E option, which includes ESI transactions in the output.

What’s new in Varnish 6.4?

if-range support

Varnish 6.4 features support for the if-range request header. The value of that header is either a date or an ETag value.

The result is that range requests are only performed if the value of the if-range header either matches the Last-Modified date of the response, or if it matches the value of the ETag response header.

Long story short: the if-range header performs conditional range requests.

Prior to Varnish 6.4, vmod_cookie had to be installed from the varnish_modules repository. You either had to compile it manually, or get it from the package manager of your operating system.

As of Varnish 6.4, vmod_cookie has been imported into the main tree and is now available by default.

vmod_cookie makes parsing, fetching, and modifying cookies a lot easier. Here’s an example:

vcl 4.1;
import cookie;

sub vcl_recv {
    if (req.http.cookie) {
        cookie.parse(req.http.cookie);
        # Either delete the ones you want to get rid of:
        cookie.delete("cookie2");
        # or delete all but a few:
        cookie.keep("SESSIONID,PHPSESSID");

        # Store it back into req so it will be passed to the backend.
        set req.http.cookie = cookie.get_string();

        # If empty, unset so the builtin VCL can consider it for caching.
        if (req.http.cookie == "") {
            unset req.http.cookie;
        }
    }
}

In Varnish Enterprise, vmod_cookieplus solves many of the same use cases in a similar way. The feature set of vmod_cookieplus is also a bit broader.

Defining none backends

In Varnish 6.4, it is possible to explicitly state that you do not want a default backend by writing backend default none;.

The symbol none is similar to NULL, null and nullptr in other languages and represents the absence of an actual backend.

Any attempt to use the none backend, which is not a backend, will result in a failure.

In some cases, specifying none as the default makes a lot of sense: for example, you might use Varnish to just generate synthetic HTTP responses.

Another use case is when you are using labels to split VCL logic into more than one VCL, and the main VCL simply jumps to other loaded VCLs through return (vcl(...)). In these cases, it does not make sense to define an actual backend in the main VCL.

Finally, vmod_goto, a Varnish Enterprise VMOD, provides dynamic backends. By using goto.dns_director() or goto.dns_backend(), none makes a good choice as the default backend.

Other VCL changes

There are also some smaller VCL changes in 6.4:

  • std.rollback(header) can be used to roll back the value of that header to its original state.
  • Numerical expressions can now be negative or negated as illustrated in the following hypothetical example: set resp.http.ok = -std.integer("-200");.
  • The += operator can be used to append data to headers and response bodies.

What’s new in Varnish 6.5?

Strict CIDR checks on ACLs

Access control lists in Varnish support hostnames, individual IP addresses, and also subnets. These subnets use the CIDR notation.

An example is 192.168.0.0/24. As of Varnish Cache 6.5, the use of a non-zero host part will result in an Address/Netmask mismatch warning during VCL compilation.

Here’s an example of a such a mismatch:

acl myAcl {
	"192.168.0.10"/24;
}

The correct notation that is enforced as of Varnish Cache 6.5, is the following:

acl myAcl {
    "192.168.0.0"/24;
}

vcc__acl__pedantic parameter

The vcc_acl_pedantic runtime parameter can turn ACL CIDR mismatch warnings into actual errors when enabled. As mentioned, these errors are triggered when the host bits of a CIDR in an ACL aren’t all-zero.

obj.can_esi

Varnish Cache 6.5 introduced the obj.can_esi variable, which returns a boolean. If the response that is stored in the object can be processed using ESI, it returns true.

A new .resolve() method

As of Varnish Cache 6.5, there is a new .resolve() method for backends and directors, which immediately resolves a backend. Explaining exactly what this means requires an understanding of what a director is. In short, a director organizes a set of backends, for example for load balancing, and selects one from the set when a backend is needed to carry out a backend request. The new .resolve() method forces the director to immediately select a concrete backend.

Note that this method is not related to DNS resolution when a backend is defined using a domain name. In these cases, the DNS lookup happens once, during compilation, and the IP address is constant throughout the lifetime of the VCL.

Read more about different types of directors in chapter 5.

Closing the connection

Varnish Cache 6.5 now allows you to explicitly close the connection in VCL, bypassing any potential keep-alive settings that were in place.

Here’s an example of how this can be accomplished in VCL:

sub vcl_backend_response {
    if (beresp.backend == faulty_backend) {
        if (beresp.http.Connection) {
            set beresp.http.Connection += ", close";
        } else {
            set beresp.http.Connection = "close";
        }
    }
}

BLOB literal syntax

Binary large objects or BLOBs as we call them, now have a new literal syntax as of Varnish Cache 6.5. The format is :<base64>:.

Here’s an example of such a literal:

:3k0f0yRKtKt7akzkyNsTGSDOJAZOQowTwKWhu5+kIu0=:

std.blobread()

Similar to std.fileread(), the new std.blobread() function will read data from disk, but it will return a BLOB rather than a string. This is ideal for reading binary files.

No connection is made to a backend administratively set as unhealthy

When a backend is explicitly set to unhealthy using varnishadm backend.set_health, Varnish will no longer attempt to connect to the backend. The unhealthy status is immediately noticed, and a HTTP 503 error is returned.

Help screen in varnishstat

If you type h in varnishstat, you’ll get a help page as of Varnish Cache 6.5, explaining the various controls.

What’s new in Varnish 6.6?

Start Varnish without a backend

The -b and -f runtime parameters are mutually exclusive. Prior to Varnish Cache 6.5 it was not possible to start Varnish without defining the none backend in your VCL file, which required using the -f option.

In Varnish Cache 6.5 it is now possible to use -b none to start the varnishd program without having to use the -f parameter.

Header validation

Headers can now be validated against the rules set by RFC7230. By default header validation doesn’t take place.

By adding the -p feature=+validate_headers runtime parameter to varnishd, header validation is enabled.

Vary notices

In Varnish Cache 6.6 the number of cache variations is now limited by the newly introduced vary_notice parameter. The default value is ten.

When the number of cache variations exceeds this value, a Notice record will be added to the Varnish Shared Memory Log (VSL).

Checking ban errors

The ban() function is now deprecated because it lacks the ability to evaluate its success. In Varnish Cache 6.6 two new ban functions were added:

  • std.ban(): performs the ban and either returns true or false depending on its success.
  • std.ban_error(): if an error occurred in std.ban(), std.ban_error() will display a detailed error message.

Here’s a tiny VCL snippet that illustrates its use:

if (std.ban(...)) {
  return(synth(200, "Ban added"));
} else {
  return(synth(400, std.ban_error()));
}

Modulus operator

Varnish Cache 6.6 added the modulus operator to VCL. This corresponds to % and can be used as follows:

vcl 4.1;

import std;

sub vcl_recv {
    set req.http.number = "4";
    if(std.integer(req.http.number) % 2 == 0) {
        return(synth(200,"Even"));
    } else {
        return(synth(200,"Odd"));
    }
}

New notation for long strings

In addition to the {" ... "} format for denoting long strings, Varnish Cache 6.6 has now added the """ ... """ format.

New built-in VCL

The built-in VCL has been reworked: VCL code has been split into small subroutines, to which custom VCL can prepend custom code.

VCL variable changes

The client.identity variable is now accessible on the backend side. Prior to the release of Varnish Cache 6.6, this variable was only accessible on the client side.

The variables bereq.is_hitpass and bereq.is_hitmiss have been added to the backend side. They match the corresponding req.is_hitpass and req.is_hitmiss that operate on the client side.

The bereq.xid variable is now also available in the vcl_pipe subroutine.

The resp.proto variable is now a read-only variable.

Backports to 6.0 LTS

Several of the features described above have been ported to the 6.0 long-term support release series of Varnish Cache, and to the corresponding Varnish Enterprise offering. The changelog for Varnish Cache 6.0 LTS releases can be found via https://varnish-cache.org/, while Varnish Enterprise changes are available at https://docs.varnish-software.com/varnish-cache-plus/changelog/changes/.


®Varnish Software, Wallingatan 12, 111 60 Stockholm, Organization nr. 556805-6203