Search

Where can you find other VMODs?

Where can you find other VMODs?

The Varnish Cache core contributors and the Varnish Software development team aren’t the only ones building VMODs.

The Varnish Cache website has a section dedicated to third-party VMODs: http://varnish-cache.org/vmods/.

You can also search on GitHub for repositories that start with libvmod-. Just have a look at the following results: https://github.com/search?q=libvmod-&type=repositories.

There are some really interesting ones there, but before you install one, make sure it is compatible with Varnish 6.

Third-party VMODs

There are a lot of good third-party VMODs out there, but there’s also some overlap with functionality that can be found in Varnish Enterprise VMODs.

Here are two third-party VMODS I really like:

  • vmod_basicauth
  • vmod_redis

vmod_basicauth

The vmod_basicauth module reads a typical Apache .htpasswd file and tries to match it to the incoming Aut``h``orization header.

Here’s an example of this VMOD:

vcl 4.1;

import basicauth;

sub vcl_recv {
	if (!basicauth.match("/var/www/.htpasswd",req.http.Authorization)) {
		return (synth(401, "Restricted"));
	}
}

sub vcl_synth {
	if (resp.status == 401) {
		set resp.http.WWW-Authenticate = {"Basic realm="Restricted area""};
	}
}

If the username and password encoded in the Authorization header don’t match an entry in .htpasswd, an HTTP 401 status code is triggered, which will result in a WWW-Authenticate: Basic realm="Restricted area" response header being synthetically returned.

This WWW-Authenticate header will trigger a server-side login popup.

For more information about this VMOD, please visit http://man.gnu.org.ua/manpage/?3+vmod-basicauth.

vmod_redis

vmod_redis provides a client API to control a Redis server. Redis is an advanced distributed key-value store and has become somewhat of an industry standard.

Here’s just a very simple example where we set up a connection and fetch the value of the foo key:

vcl 4.1;

import redis;

sub vcl_init {
	new db = redis.db(
		location="192.168.1.100:6379",
		connection_timeout=500,
		shared_connections=false,
		max_connections=2);
}

sub vcl_deliver {
	db.command("GET");
	db.push("foo");
	db.execute();
	set resp.http.X-Foo = db.get_string_reply();
}

But the API for this VMOD is extensive and supports some of the following features:

  • Working with clustered and replicated setups
  • Running LUA scripts
  • Evaluating various return types
  • Request pipelining
  • Leveraging the various Redis data types

For more information about this VMOD, please visit https://github.com/carlosabalde/libvmod-redis.

The Varnish Software VMOD collection

Varnish Software also has a GitHub repository with some open source VMODs. You can find the code on https://github.com/varnish/varnish-modules.

These modules are also packaged with Varnish Enterprise. Here is the list of VMODs that are part of this collection:

  • vmod_bodyaccess
  • vmod_header
  • vmod_saintmode
  • vmod_tcp
  • vmod_var
  • vmod_vsthrottle
  • vmod_xkey

Let’s do a walkthrough, and look at some VCL examples for a couple of these VMODs.

vmod_bodyaccess

vmod_bodyaccess is a very limited version of vmod_xbody. Whereas vmod_xbody has read and write access to request and response bodies, vmod_bodyaccess only has read access to the request body.

Here’s a list of features that this VMOD provides:

  • Search for regular expression pattern in the request body
  • Hash the request body
  • Get the request body length
  • Log the request body to VSL

Let’s have a look at a VCL example where we’ll use vmod_bodyaccess in a scenario where we’ll cache POST requests:

vcl 4.1;

import std;
import bodyaccess;

sub vcl_recv {
	set req.http.x-method = req.method;
	if (req.method == "POST") {
		if (std.cache_req_body(110KB)) {
			if (bodyaccess.rematch_req_body("id=[0-9]+")) {
				return (hash);
			}
			return (synth(422, "Missing ID");
		}
		return (synth(413));
	}
}

sub vcl_hash {
	bodyaccess.hash_req_body();
}

sub vcl_backend_fetch {
	set bereq.method = bereq.http.x-method;
}

None of this works unless std.cache_req_body() is called. This starts caching the request body. bodyaccess.rematch_req_body("id=[0-9]+") is used to figure out whether or not the id=[0-9]+ pattern is part of the request body. When the pattern matches, we’ll decide to cache. If the payload is too large or the ID is missing an error will be generated instead.

bodyaccess.hash_req_body() is used in vcl_hash to create a cache variation for each request body value.

This is the HTTP request you can send to trigger this behavior:

POST / HTTP/1.1
Host: localhost
Content-Length: 4
Content-Type: application/x-www-form-urlencoded

id=1

vmod_header

vmod_header allows you to get headers, append values to headers, and remove values from headers. It’s a very limited VMOD in terms of functionality, and pales in comparison to vmod_headerplus.

Here’s a quick example, just for the sake of it:

vcl 4.1;

sub vcl_backend_response {
	header.remove(beresp.http.foo, "one=1");
}

Imagine the following HTTP response headers:

HTTP/1.1 200 OK
Foo: one=1
Foo: one=2

The response contains two instances of the Foo header, each with different values. The example above will ensure that the first occurrence of the header that matches the pattern is removed.

Foo``: one=1 matches that pattern and is removed. Only Foo: one=2 remains.

vmod_tcp

The TCP VMOD allows you to control certain aspects of the underlying TCP connection that was established.

The first example will enable rate limiting for incoming connections:

vcl 4.1;

import tcp;

sub vcl_recv
{
	tcp.set_socket_pace(1024);
}

This example will pace the throughput at a rate of 1024 KB/s.

In the second example the BBR congestion algorithm is used for TCP connections:

vcl 4.1;

import tcp;

sub vcl_recv {
	tcp.congestion_algorithm("bbr");
}

This requires that the BBR congestion controller is both available and loaded.

vmod_var

VCL clearly lacks the concept of variables. Although headers are commonly used to transport values, the values are usually cast to strings, and one needs to have the discipline to strip off these headers before delivering them to the backend or the client.

vmod_var offers variable support for various data types.

The supported data types are:

  • strings
  • integers
  • real numbers
  • durations
  • IP addresses
  • backends

Here’s the VCL example to illustrate some of the VMOD’s functions:

vcl 4.1;

import var;
import std;

sub vcl_recv {
	var.set_ip("forwarded",std.ip(req.http.X-Forwarded-For,"0.0.0.0"));
	var.set_real("start",std.time2real(now,0.0));
}

sub vcl_deliver {
	set resp.http.forwarded-ip = var.get_ip("forwarded");
	set resp.http.start = std.real2time(var.get_real("start"),now);
}

This example will use the std.ip() function from vmod_std to turn the X-Forwarded-For header into a valid IP type. The value is stored using var.set_ip().

The current time is also stored as a real type, using std.time2real() to convert the type.

In a later stage, we can retrieve the information using the corresponding getter functions.

vmod_vsthrottle

We’ve already seen rate limiting when we talked about vmod_tcp. But rate limiting also happens in this VMOD.

In vmod_vsthrottle, we’re restricting the number of requests a client can send in a given timeframe.

Take for example, the VCL code below:

vcl 4.1;

import vsthrottle;

sub vcl_recv {
	if (vsthrottle.is_denied(client.identity, 15, 10s, 30s)) {
		return (synth(429, "Too Many Requests. You can retry in " 
		+ vsthrottle.blocked(client.identity, 15, 10s, 30s) 
		+ " seconds."));
	} 
}

This code will only allow clients to perform 15 requests in a 10 second timeframe. If that rate is exceeded, the user gets blocked for 30 seconds.

The vsthrottle.is_denied() function is responsible for that. The vsthrottle.blocked() is also quite helpful, as it returns the number of seconds the user is still blocked.

This allows us to set expectations. This is the error messages that users get when they are blocked due to rate limiting:

Too Many Requests. You can retry in 26.873 seconds.

In this case, the user knows they should wait another 26 seconds before attempting to perform another request.

vmod_xkey

We already mentioned that vmod_xkey is the predecessor of vmod_ykey, basically the open source version. It doesn’t work when using MSE, but if you’re using Varnish Cache, that is not a concern.

The API is also more limited, as you are forced to tag objects using the xkey response header, and you cannot add extra tags in VCL.

Here’s the VCL example to show how you can remove objects from cache using vmod_xkey:

vcl 4.1;

import xkey;

sub vcl_recv {
	if (req.method == "PURGE" && req.http.x-xkey-purge) {
		if (xkey.purge(req.http.x-xkey-purge) != 0) {
			return(synth(200, "Purged"));
		}
		return(synth(404, "Key not found"));
	}
}

If you’re performing a PURGE call, you can use the x-xkey-purge request header to specify the keys you want to use for purging. The keys are space-delimited.

Imagine we want to remove all the objects that are tagged with the js and css tags. You’d need to send the following HTTP request:

PURGE / HTTP/1.1
x-xkey-purge: js css

The response would be HTTP/1.1 200 Purged if the keys were found or HTTP/1.1 404 Key not found when there are no corresponding keys.

Please note that you usually want to limit such functionality behind ACL. In the next chapter, we’ll talk about cache invalidation, and we’ll cover the vmod_xkey in more detail as well.

How to install these VMODs

We always advise you to install Varnish Cache using our official packages. These are available on https://packagecloud.io/varnishcache. However, we don’t provide packages for the VMOD collection. This means you’ll have to compile them from source.

Compiling from source

You can get the source code from https://github.com/varnish/varnish-modules. But for Varnish Cache 6.0 and Varnish Cache 6.0 LTS, you need to download the code from the right branch:

There are some build dependencies that need to be installed. On a Debian or Ubuntu systems, you can install them using the following command:

# apt-get install -y varnish-dev autoconf automake gcc libtool make python3-docutils

On Red Hat, Fedora, and CentOS systems, you can use the following command to install the dependencies:

# yum install -y varnish-devel autoconf automake gcc libtool make python3-docutils

Once all build dependencies are in place, you can compile the VMODs by running the following commands in the directory where the VMOD source files were extracted:

./bootstrap
./configure
make
make install

After having run make install, the corresponding .so files for these VMODs can be found in the path that was defined by the vmod_dir runtime parameter in Varnish.

Debian and Ubuntu distro packages

The Debian and Ubuntu distributions also offer Varnish Cache via their own packages. Some versions still provide the varnish-modules package, which is Debian and Ubuntu’s version of the VMOD collection.

Installing these VMODS is done using this very simple command:

# apt-get install varnish-modules

The following version of Debian and Ubuntu offer the varnish-modules package for Varnish Cache 6:

  • Ubuntu 20.10 (Groovy) offers Varnish Cache 6.4.0.
  • Debian 10 (Buster) offers Varnish Cache 6.1.1.
  • Debian 11 (Bullseye) offers Varnish Cache 6.4.0.

Although we advise installing Varnish Cache 6.0 LTS from our official packages, there’s no denying that it’s easy to just install Varnish using a simple apt-get install varnish command.


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