A VMOD is a shared library that is written in C. It has a set of
functions, containing the logic it wants to expose. These functions
can then be imported and called from VCL, which in turn adds new
functionality to VCL.
This is a very powerful concept because anything that can be written in
C can in fact be exposed to VCL.
Varnish isn’t just a cache: by using the right VMODs, you can reshape content, route traffic, use custom authentication mechanisms and implement all kinds of custom logic using powerful VMODs.
However, it is important to know that VMODs aren’t a gateway to Varnish’s inner workings: the APIs that Varnish provides are quite limited, and there aren’t a lot of hooks. VMODs are intended to act independently, and usually wrap around some sort of library or logic in a simple and easy-to-use manner.
Some of the VMODs that are shipped with Varnish go beyond basic wrapping and do interface with the Varnish core. But that’s because the core has patches to open up access to internal APIs, purpose-built for these VMODs
The majority of VMODs perform the following tasks:
Every VMOD has an API. It is a collection of function calls and objects that the module exposes to VCL.
The VCL API is kept in a .vcc file, and one or more .c files
contain the actual code.
Take for example https://github.com/varnishcache/libvmod-example,
where you find the source code of the vmod_example VMOD.
vmod_exampleis a sample module for aspiring VMOD writers who need a bit of inspiration. The module itself doesn’t really do much, but it does lead the way, contains the necessary files, and scripts to build the module.
In the src directory, you’ll find a vmod_example.vcc file that
contains the API.
$Module example 3 Example VMOD
DESCRIPTION
===========
This is the embedded documentation for the example VMOD. It should explain
the purpose and what problems it solves, with relevant examples.
It can span multiple lines and is written in RST format.
You can even have links and lists in here:
* https://github.com/varnish/libvmod-example/
* https://www.varnish-cache.org/
$Event event_function
$Function STRING info()
Returns a string set by the last VCL event, demonstrating the use of
event functions.
$Function STRING hello(STRING)
The different functions provided by the VMOD should also have their own
embedded documentation. This section is for the hello() function.
The $Module line defines the name of the VMOD, and the $Function
lines define the API. The example above contains two functions:
example.info() which returns the information about the last VCL
event that occurredexample.hello() which performs the typical Hello World, based on
an input argumentThe corresponding code can be found in vmod_example.c. The C-code
itself isn’t that important to VMOD users, because the idea is that
the VCL functions are the interface, and the implementation is
abstracted by these VCL functions. As long as the documentation for
the VMOD is good, the code is irrelevant.
Our example VMOD can be loaded into our VCL file by using the
import statement:
vcl 4.1;
import example;
sub vcl_deliver {
	set resp.http.hello = example.hello("Thijs");
}
As you can see the example.hello() function becomes available and can
be used in any of the VCL subroutines. In the example above, we’re
using it to set the following response header:
hello: Hello Thijs
VMODs aren’t always a collection of utility functions. Often they keep track of state and are grouped into one or more objects.
Setting them up may require an initialization stage, which is done in
the vcl_init subroutine. Throughout the book, we haven’t mentioned
this subroutine a lot.
Let’s immediately throw in an example where vcl_init initializes
vmod_directors:
vcl 4.1;
import directors;
backend backend1 {
	.host = "backend1.example.com";
	.port = "80";
}
backend backend2 {
	.host = "backend2.example.com";
	.port = "80";
}
sub vcl_init {
	new vdir = directors.round_robin();
	vdir.add_backend(backend1);
	vdir.add_backend(backend2);
}
sub vcl_recv {
	set req.backend_hint = vdir.backend();
}
This VMOD creates a director object that groups multiple backends into
one. The director will distribute load across these backends using a
distribution algorithm, and will expose itself as a single backend using
the .backend() function.
Adding backends and choosing the right distribution algorithm is all
done in vcl_init. As you can see in the example above, we’re using the
directors.round_robin() function to create a directors object named
vdir. This object uses the vdir.add_backend() method to assign
backends.
vmod_directorsis a load-balancing VMOD and will be covered in detail in chapter 7.
Installing a VMOD is a lot like compiling C-code. That’s because a
VMOD is written in C.
VMODs come with an autogen.sh script that will inspect your
operating system, and will determine where to find the libtoolize,
autoconf, and automake tools. The script also looks for the
varnishapi library.
After this script finishes its execution, you can run the configure
script that was generated. This script will configure the GCC
compiler.
Eventually, all the configurations are in place to run the make
command, which will use a Makefile to compile specific source files.
The final step is running make install, which will turn the compiled
files into libvmod_example.so, and put this shared object in the
right directory. By default this is /usr/lib/varnish/vmods/.
In order to successfully compile and install a VMOD your build system will have some dependencies.
If you’re on a Debian or Ubuntu system, you can use the following command to install the required dependencies:
# apt update && apt install -y \
varnish build-essential automake libtool python3-docutils
If you’re on Red Hat, Fedora, or CentOS, this is the equivalent:
# yum check-update && yum install -y \
varnish-devel gcc make automake libtool python3-docutils
It’s worth mentioning that you generally don’t have to compile or install any VMODs yourself, as most of them are packaged either with Varnish Cache or with Varnish Enterprise. It’s only for when you are developing your own VMODs, or when you are using non-packaged community VMODs.