Extra Varnish Cache features

The Varnish Cache distribution packages a set of extra features that aren’t available out of the box in Vinyl Cache.

On top of the bundled VMODS, Varnish Cache packages the following extra modules:

Varnish-Software Vmods

Third Party Packaged Unofficial Vmods

Let’s take a look at some of the capabilities of these modules on a per-VMOD basis.

vmod-accept

The accept VMOD sanitizes content-negotiation headers like Accept, Accept-Charset, Accept-Encoding and Accept-Language.

Sanitizing and normalizing these accept headers is important when cache variations take place: backends can return different responses for the same URL based on the value of a request header. If for example an application has support for multiple languages based on the conventional Accept-Language header, you want to minimize the amount of variations that happen.

By normalizing the supported values, the number of unnecessary variations is reduced. Here’s an example that normalizes the Accept and Accept-Language headers:

vcl 4.1;w

import accept;

sub vcl_init {
    # Only support plain text, HTML & JSON.
    # Use plain text as a fallback in case the value doesn't match.
    new format = accept.rule("text/plain");
    format.add("text/plain");
    format.add("text/html");
    format.add("application/json");

    # Only allow English & French content
    # Fall back to English when the value doesn't match
    new lang = accept.rule("en");
    lang.add("en");
    lang.add("fr");
}

sub vcl_recv {
    # Overwrite headers with the normalized values
    set req.http.accept = format.filter(req.http.accept);
    set req.http.accept-language = lang.filter(req.http.accept-language);
}

This example only supports text/plain, text/html and application/json as valid Accept header values. Any other value triggers text/plain as the fallback. The example only supports en and fr as valid languages, any other value falls back to en.

This module is part of the Varnish module collection by Varnish Software.

vmod-bodyaccess

The bodyaccess VMOD provides an API to access the request body:

  • bodyaccess.rematch_req_body() lets you match a regular expression to the request body
  • bodyaccess.hash_req_body() adds the request body to the cache lookup hash
  • bodyaccess.len_req_body() returns the length of the request body
  • bodyaccess.log_req_body() logs the request body in the Varnish Shared Memory Logs

Here’s a VCL example that uses vmod_bodyaccess:

vcl 4.1;
import std;
import bodyaccess;

sub vcl_recv {
    if (req.method == "POST") {
        set req.http.x-method = req.method;
        if (std.cache_req_body(110KB)) {
            set req.http.x-len = bodyaccess.len_req_body();
            set req.http.x-re = bodyaccess.rematch_req_body("Regex");
            bodyaccess.log_req_body("PREFIX:", 250);
        }
    }
    return(hash);
}

sub vcl_hash {
        bodyaccess.hash_req_body();
        return (lookup);
}

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

sub vcl_deliver {
        set resp.http.x-len = req.http.x-len;
        set resp.http.x-re = req.http.x-re;
}

This VCL example overrides the standard caching behavior and allows HTTP POST requests to be cached. std.cache_req_body(110KB) ensures the request body can only be 110 KB in size before adding that request body to the cache lookup hash. The example stores the request body length in the custom x-len request header while storing the result of a regular expression match for Regex in the x-re request header.

A cache lookup is forced regardless of the HTTP request header and when performing the cache lookup, the request body is added to the lookup hash. For debugging purposes the body length and regular expression matches that were stored in custom request headers, these values end up in the x-len and x-re response headers.

This module is also part of the Varnish module collection by Varnish Software.

vmod-header

The header VMOD exposes an API that facilitates manipulation of duplicated HTTP headers.

There are situations where certain headers appear multiple times. This VMOD allows you to add, delete, modify and delete these headers.

Here’s an example where Set-Cookie headers are manipulated:

vcl 4.1;
import header;

sub vcl_backend_response {
    if (beresp.http.Set-Cookie) {
        # Add another line of Set-Cookie in the response.
        header.append(beresp.http.Set-Cookie, "VSESS=abbabeef");

        # CMS always set this, but doesn't really need it.
        header.remove(beresp.http.Set-Cookie, "JSESSIONID=");
    }
}

This example adds an additional Set-Cookie response header and uses VSESS=abbabeef as its value. At the same time Set-Cookie headers are removed if the value contains JSESSIONID=.

This module is also part of the Varnish module collection by Varnish Software.

vmod-saintmode

The saintmode VMOD marks backends as sick for specific objects during a certain amount of time. It does this based on a deny list, and as long as a backend has an object on that list, these objects will not be served by this backend.

When the number of objects marked as sick for a backend exceeds the threshold, the entire backend is marked as sick.

Here’s a VCL example that features vmod_saintmode:

vcl 4.1;

import saintmode;
import directors;

backend b1 { .host = "192.0.2.11"; .port = "80"; }
backend b2 { .host = "192.0.2.12"; .port = "80"; }

sub vcl_init {
    # Instantiate sm1, sm2 for backends b1, b2
    # with 10 denylisted objects as the threshold for marking the
    # whole backend sick.
    new sm1 = saintmode.saintmode(b1, 10);
    new sm2 = saintmode.saintmode(b2, 10);

    # Add both to a director. Use sm1, sm2 in place of b1, b2.
    # Other director types can be used in place of random.
    new loadbalancer = directors.random();
    loadbalancer.add_backend(sm1.backend(), 1);
    loadbalancer.add_backend(sm2.backend(), 1);
}

sub vcl_backend_fetch {
    # Get a backend from the director.
    # When returning a backend, the director will only return backends
    # saintmode says are healthy.
    set bereq.backend = loadbalancer.backend();
}

sub vcl_backend_response {
    if (beresp.status >= 500) {
        # This marks the backend as sick for this specific
        # object for the next 20s.
        saintmode.denylist(20s);
        # Retry the request. This will result in a different backend
        # being used.
        return (retry);
    }
}

This example puts vmod-saintmode in front of the 2 backends and marks each backend as sick when it has 10 items on the deny list. Individual responses that return a status code that is greater than 500 are added to the deny list and cause the backend to be marked as sick for these objects. Objects are only added to the deny list for 20 seconds.

This module is also part of the Varnish module collection by Varnish Software.

vmod-str

The str VMOD is a utility module for strings that supports counting, substrings, splitting and various types of matching.

Here’s a VCL example:

vcl 4.1;

import str;

sub vcl_deliver {
    # Only perform these actions for iPads
    if(str.contains(req.http.User-Agent, "iPad")) {
        # Returns the ASCII character count of the User-Agent value
        set resp.http.ua-count = str.count(req.http.User-Agent);
        # Stores the first 10 characters of the User-Agent
        set resp.http.ua-first-10 = str.take(req.http.User-Agent, 10);
    }
}

This module is also part of the Varnish module collection by Varnish Software.

vmod-tcp

The tcp VMOD contains functions to control TCP congestion control algorithms, throttling and perform logging of protocol-related information.

Here’s a throttling example where all clients are limited to 1000 KB/s:

vcl 4.1;

import tcp;

sub vcl_recv {
  # Limit all clients to 1000 KB/s.
  tcp.set_socket_pace(1000);
}

This module is also part of the Varnish module collection by Varnish Software.

vmod-var

The var VMOD offers basic variable support in VCL. It supports strings, integers, real numbers, durations, IP addresses and backends. There are methods to get and set each data type.

Both global and local variables are supported in vmod-var. Here’s a VCL example:

vcl 4.1;
import var;

sub vcl_recv {
    # Set and get some values.
    var.set("foo", "bar");
    set req.http.x-foo = var.get("foo");

    var.set_int("ten", 10);
    var.set_int("five", 5);
    set req.http.twenty = var.get_int("ten") + var.get_int("five") + 5;

    # VCL will use the first token to decide on the final data type.
    # set req.http.X-lifetime = var.get_int("ten") + " seconds"; #  Won't work.
    set req.http.X-lifetime = "" + var.get_int("ten") + " seconds";  # Works!

    var.set_duration("timedelta", 1m);  # 60s
    set req.http.d1 = var.get_duration("timedelta");

    var.set_ip("endpoint", client.ip);
    set req.http.x-client = var.get_ip("endpoint");

    # Unset all non-global variables.
    var.clear();

    # Demonstrate use of global variables as state flags.
    if (req.url ~ "/close$") {
        var.global_set("open", "no");
    }
    else if (req.url ~ "/open$") {
        var.global_set("open", "yes");
    }

    if (var.global_get("open") != "yes") {
        return (synth(200, "We are currently closed, sorry!"));
    }
}

This module is also part of the Varnish module collection by Varnish Software.

vmod-vsthrottle

The vsthrottle vmod allows for rate limiting traffic on a single Varnish server. The VMOD offers a simple interface for rate limiting traffic on a per-key basis to a specific request rate.

Here’s a simple VCL example that illustrates the different types of key-based rate limiting:

vcl 4.1;

import vsthrottle;

sub vcl_recv {
  # Varnish will set client.identity for you based on client IP.

  if (vsthrottle.is_denied(client.identity, 15, 10s, 30s)) {
    # Client has exceeded 15 reqs per 10s.
    # When this happens, block altogether for the next 30s.
    return (synth(429, "Too Many Requests"));
  }

  # There is a quota per API key that must be fulfilled.
  if (vsthrottle.is_denied("apikey:" + req.http.Key, 30, 60s)) {
      return (synth(429, "Too Many Requests"));
  }

  # Only allow a few POST/PUTs per client.
  if (req.method == "POST" || req.method == "PUT") {
    if (vsthrottle.is_denied("rw" + client.identity, 2, 10s)) {
      return (synth(429, "Too Many Requests"));
    }
  }
}

The first check rate limits clients based on their IP address and allows 15 requests in a 10-second timeframe. If the rate limit is exceeded, any request from that client returns a 429, Too Many Requests error for the next 30 seconds.

The next check adds an extra rate limit based on the Key request header: 30 requests are allowed within a 60-second timeframe.

The final check limits HTTP POST and PUT requests per IP address at 2 requests in a 10-second timeframe.

This module is also part of the Varnish module collection by Varnish Software.

vmod-xkey

The xkey VMOD offers surrogate key support for Varnish. This means that secondary hashes are added to objects that are not based on the URL or Host header. This allows for fast purging of objects based on arbitrary keys. One could consider these secondary hashes to be tags, offering tag-based cache invalidation to Varnish.

Here’s a VCL example:

vcl 4.1;

import xkey;

acl purgers {
    "203.0.113.0"/24;
}

sub vcl_recv {
    if (req.method == "PURGE") {
        if (client.ip !~ purgers) {
            return (synth(403, "Forbidden"));
        }
        if (req.http.xkey) {
            set req.http.n-gone = xkey.purge(req.http.xkey);
            # or: set req.http.n-gone = xkey.softpurge(req.http.xkey)
            return (synth(200, "Invalidated "+req.http.n-gone+" objects"));
        } else {
            return (purge);
        }
    }
}

This example provides an alternative cache purging interface that leverages the PURGE request method. The standard implementation triggers return(purge) to purge objects based on the URL. However, by adding a xkey request header, the VCL code uses the key to match objects instead. All objects that were tagged with that key will be matched and purged.

The xkey.purge() method performs hard purges, meaning that matched objects are immediately removed from the cache and cause cache misses. The xkey.softpurge() method has similar behavior, but marks objects as expired, rather than remove them immediately.

The soft purge behavior leverages the grace mechanism, which is Varnish’s implementation of stale-while-revalidate. Soft-purged objects have a TTL of zero, but if there’s grace left, the object is still served from the cache, while an asynchronous fetch to the backend takes place to update the object.

Tagging objects is done by setting the xkey response header. Here’s an example response that contains the xkey header:

HTTP/1.1 OK
Server: Apache
xkey: 8155054 166412 234323

Varnish picks up the xkey header and adds 8155054, 166412, and 234323 as secondary hashes.

The following HTTP request can be made to match the second key:

PURGE / HTTP/1.1
Host: www.example.com
xkey: 166412

Every object that is tagged with 166412 is matched and purged through this PURGE request.

This module is also part of the Varnish module collection by Varnish Software.

vmod-cfg

The cfg VMOD provides easy access to environment variables and local or remote (config) files in VCL.

The module supports the following file types:

  • JSON files
  • .ini files
  • Lua scripts
  • ECMAScript
  • Files containing collections of pattern matching rules

Besides reading the configuration files, vmod-cfg can also execute Lua & Javascript locally.

Local ini file example

Here’s an example of an .ini file that we’ll use in the VCL code. We’ll call this one vcl.ini

hello: world

[more]
foo: bar
hello: world

We’ll make the path to this file dynamic and store it in an environment variable:

export VCL_SETTINGS=file:///etc/varnish/vcl.ini

Now we can load the environment variable and use its value to load and parse the vcl.ini file:

vcl 4.1;

import cfg;

backend default none;

sub vcl_init {
    new env = cfg.env();

    if (env.is_set("VCL_SETTINGS")) {
        new settings = cfg.file(env.get("VCL_SETTINGS"));
    } else {
        return (fail);
    }
}

sub vcl_recv {
    return(synth(200));
}

sub vcl_synth {
    set resp.http.Content-Type = "text/plain";
    if(settings.is_set("more:hello")) {
        set resp.body = "Hello " + settings.get("more:hello");
    } else {
        set resp.body = "Settings not available";
    }
    return(deliver);
}

This example returns Hello world if the VCL_SETTINGS environment variable is set, if the referenced file can be loaded, and if it contains the more:hello key. Otherwise it just returns Settings not available.

Javascript example

Here’s another example that loads remote files and executes Javascript locally.

This is the Javascript file that is run locally inside Varnish:

return "Foo " + ARGV[0]

We’ll call this file script.js and store it in /etc/varnish. Here’s the VCL code:

vcl 4.1;

import cfg;

backend default none;

sub vcl_init {
    new settings = cfg.file("https://www.example.com/settings.json", format=json);
    new script = cfg.script("file:///etc/varnish/script.js", type=javascript);
}

sub vcl_recv {
    return(synth(200));
}

sub vcl_synth {
    set resp.http.Content-Type = "text/plain";
    if(settings.is_set("foo")) {
        script.init();
        script.push(settings.get("foo"));
        script.execute();
        set resp.body = script.get_result();
        script.free_result();
    } else {
        set resp.body = "Settings not available";
    }
    return(deliver);
}

This example fetches settings.json remotely from https://www.example.com/settings.json and parses the JSON content. Here’s the output:

{
    "foo": "bar"
}

The VCL example also loads the local script.js file and instantiates it as Javascript. If the settings.json file returns a foo property, the value of that property is passed to the Javascript as an argument.

This means the output will be Foo bar. If the remote settings cannot be loaded, the fallback output is Settings not available.

More information about this VMOD is available on the corresponding GitHub repository.

vmod-digest

The digest VMOD allows for computing HMAC signatures, create hashes and working with base64.

Here’s an example where we validate a SHA256-encoded HMAC signature that get stored in the x-data-sig request header:

vcl 4.1;

import digest;

sub vcl_recv {
    if (digest.hmac_sha256("key",req.http.x-data) != req.http.x-data-sig) {
        return (synth(401));
    }
}

This example compares the HMAC signature that is stored in the x-data-sig request header to the new HMAC signature that is generated based on the payload of the x-data request header.

The secret key that is used the generate that HMAC is key. It is recommended to make the secret key more complex, have the ability to regularly change the key, and potentially fetch the secret key from a secure external source.

More information about vmod-digest is available on the corresponding GitHub repository.

vmod-fileserver

The fileserver VMOD serves files directly from Varnish without needing an external backend.

Here’s an example where files are directly served from the /var/www/html folder on the Varnish server:

vcl 4.1;

import fileserver;

backend default none;

sub vcl_init {
	new www = fileserver.root("/var/www/html");
}

sub vcl_recv {
	set req.backend_hint = www.backend();
}

More information can be found on the vmod-fileserver GitHub repository.

vmod-geoip2

The geoip2 VMOD reads MaxMind GeoIP2 database files and returns geolocation information for IP addresses.

Here’s a VCL example where we only allow access to users from Sweden and Germany, but we log the country and city of the client:

vcl 4.1;

import geoip2;
import std;

sub vcl_init {
    new geo = geoip2.geoip2("/etc/varnish/GeoLite2-City.mmdb");
}

sub vcl_recv {
    set req.http.x-city = geo.lookup("city/names/en", client.ip);
    set req.http.x-country-name = geo.lookup("country/names/en", client.ip);
    set req.http.x-country-iso = geo.lookup("country/iso_code", client.ip);

    std.log("city: " + req.http.x-city);
    std.log("country: " + req.http.x-country-name);
    std.log("country-iso: " + req.http.x-country-iso);

    if(req.http.x-country-iso != "SE" && req.http.x-country-iso != "DE") {
        return(synth(401,"Content not available in " + req.http.x-country-name));
    }
}

The GeoIP databases can be download from the Maxmind website. More information about vmod-geoip2 is available on the corresponding GitHub repository.

vmod-jq

The jq VMOD parses JSON and offers a clean API to access individual properties. It is based on the jq program and offers similar filtering capabilities.

This VMOD can parse arbitrary strings, but can also access the request body. Here’s an example of a JSON request body being parsed:

vcl 4.1;

import jq;
import std;
backend default none;

sub vcl_recv {
    std.cache_req_body(1KB);
    return(synth(200));
}

sub vcl_synth {
    set resp.http.Content-Type = "text/plain";
    jq.parse(request);
    if(jq.length() > 0) {
        set resp.body = jq.get(".foo.bar", "Fallback value", raw=1);
    }
    return(deliver);
}

This example expects the following request body:

{
    "foo": {
        "bar": "Hello world"
    }
}

The response that Varnish returns is either the value of .foo.bar or Fallback value as the fallback value in case of an error.

The following curl command send the right request body to Varnish and gets Hello world as the response:

curl -X POST http://localhost/ \
  -H "Content-Type: application/json" \
  -d '{ "foo": { "bar": "Hello world" } }'

More information about vmod-jq is available on the corresponding GitHub repository.

vmod-querystring

The querystring VMOD inspects, filters, cleans and manipulate URL querystring parameters and application/x-www-form-urlencoded strings.

Here’s an example where specific querystring parameters are removed from the URL:

vcl 4.1;

import querystring;

sub vcl_init {
    new qf = querystring.filter(sort = true);
    qf.add_glob("utm_*"); # google analytics parameters
    qf.add_regex("sess[0-9]+"); # anti-CSRF token
}

sub vcl_recv {
    set req.url = qf.apply();
}
  • This example alphabetically sorts the querystring parameters
  • It removes Google Analytics parameters that start with utm_
  • It removes session parameters like &sess1234=96BE2C35-7929-4011-A9BE-F4E8C44E4576

If you request http://localhost?hello=world&x=4&a=b&utm_z=xyz&sess1234=96BE2C35-7929-4011-A9BE-F4E8C44E4576, this example internally rewrites the URL to http://localhost/?a=b&hello=world&x=4. By removing unnecessary query string parameters from the URL, you improve the hit rate of the cache.

More information about vmod-querystring is available at the https://git.sr.ht/~dridi/vmod-querystring.

vmod-redis

The redis VMOD offers a Redis client API allowing your VCL code to interact with a Redis server.

Here’s a VCL example that queries a Redis server for user access information based on a session cookie:

vcl 4.1;

import redis;
import cookie;

sub vcl_init {
    new db = redis.db(location="localhost:6379");
}

sub vcl_recv {
    if(req.url ~ "^/admin(/|$)") {
        cookie.parse(req.http.Cookie);
        if(!cookie.isset("SESSIONID")) {
            return(synth(401));
        }

        db.command("HGET");
        db.push(cookie.get("SESSIONID"));
        db.push("allowed");
        db.execute();

        if(db.get_string_reply() != "true") {
            return(synth(403));
        }
    }
}

This example uses the SESSIONID cookie to retrieve a hash object from the Redis server. The allowed field from the hash object that is identified by its sessionid dictates whether the user is allowed to access the admin pages.

If the Redis server doesn’t respond with true a 403 Forbidden response is returned.

More information about vmod-redis is available on the corresponding GitHub repository.

vmod-reqwest

The reqwest VMOD sends and receives HTTP requests in VCL. It is used to communicate with third-party servers, but also provides dynamic backends in Varnish.

Dynamic backend example

Here’s a VCL example that showcases the dynamic backend capabilities of vmod-reqwest:

vcl 4.1;

import reqwest;

backend default none;

sub vcl_init {
	# note that "/sub/directory" will be prefixed to `bereq.url`
	# upon sending the request to the backend
	new be = reqwest.client(base_url = "https://www.example.com/sub/directory", follow = 5, auto_brotli = true);
}

sub vcl_recv {
	set req.backend_hint = be.backend();
}

This example creates a dynamic backend that routes all traffic to www.example.com over HTTPS. Up to 5 redirections are followed, and support automatic Brotli decompression.

Because the base_url parameter points to the /sub/directory path, this path is added as a prefix to all backend requests. If someone requests http://localhost/test, the actual backend request will be https://www.example.com/sub/directory/test.

If the www.example.com hostname resolves to another hostname, the VCL code notices the changes and re-route accordingly.

This feature circumvents some of the limitations of Vinyl Cache:

  • Vinyl Cache only supports static backends
  • Vinyl Cache can only connect to backends using plain HTTP

Synchronous third-party request example

Here’s an example where vmod-reqwest is used to perform requests to thir-party servers:

vcl 4.1;

import reqwest;

sub vcl_init {
	new client = reqwest.client();
}

sub vcl_recv {
	# use an HTTP request to grant (or not) access to the client
	client.init("sync", "https://api.example.com/authorized/" + req.http.user);
	if (client.status("sync") != 200) {
		return (synth(403));
	}
	# grab a response header ("id-header") and save it to our VCL request
	set req.http.user-id = client.header("sync", "id-header");
}

This example takes the user request header that is received by Varnish and appends it to https://api.example.com/authorized/. If that request returns a 200 status the id-header response header is copied into the user-id request header of the main Varnish request.

If the third-party service returns anything else than a 200 status, a 403 Forbidden response is returned.

Asynchronous third-party request example

Here’s another example where the VCL code triggers an HTTP call to an external endpoint:

vcl 4.1;

import reqwest;

sub vcl_init {
	new client = reqwest.client();
}

sub vcl_recv {
	# send a request into the void and don't worry if it completes or not
	client.init("async", "https://api.example.com/log", "POST")
	client.set_body("async", "URL = " + req.url);
	client.send("async");
}

This example sends an asynchronous POST request to https://api.example.com/log with URL = ... as the request body. This is a fire and forget request where we don’t care about the response.

vmod-rers

The rers VMOD expands the possibilities of standard regular expression in VCL and offers support for Rust-based regular expressions.

Besides the clean API to capture, match, group and replace strings, vmod-rers offers some advanced capabilities:

  • Capture values from the request body based on regular expressions
  • Change the response body based on regular expression replacements

Regular expression matching example

The first example performs a regular expression match on the URL, and captures specific patterns from the Authorization header:

vcl 4.1;

import rers;

sub vcl_init {
	new re_cache = rers.init(100);
}

sub vcl_recv {
	if (re_cache.is_match(req.url, "admin")) {
		return (pass);
	}
	if (re_cache.capture(req.http.Authorization, "(\w+) (\S+)")) {
		set req.http.auth_type = re_cache.group(1);
		set req.http.auth_credential = re_cache.group(2);
	}
}

This example looks for admin in the URL and bypasses the cache when it matches. For non-admin content, the example captures values from the Authorization header and stores them in custom headers by leveraging access to captured groups.

Request body captureing example

The next example captures values from the request body and stores these values in custom headers:

vcl 4.1;

import rers;
import std;

sub vcl_init {
	new re_cache = rers.init(100);
}

sub vcl_recv {
    std.cache_req_body(100B);
    if (re_cache.capture_req_body("(?:^|&)name=([^&]*)")) {
        set req.http.x-name = re_cache.group(1);
    }
}

This example extract the name field from the request body and stores its value in the custom x-name request header. The following curl command triggers this action:

curl -XPOST -d "x=y&name=John&b=1" http://localhost

Despite the different key/value pairs in the request body, captured group extracts the right value.

Response body manipulation example

The next example uses vmod-rers to perform regular expression-based find and replace actions on the response body:

vcl 4.1;

import rers;

sub vcl_init {
	new re_cache = rers.init(100);
}

sub vcl_deliver {
    re_cache.replace_resp_body("Welcome (\w+)!", "Welcome to my website!");
    set resp.filters = "rers";
}

This example replaces the Welcome (\w+)! pattern in the response body with Welcome to my website!. Because the replacement happens in vcl_deliver, the result is not stored in the cache, but is computed every time a result is returned.

By moving this logic to vcl_backend_response, you can store the result in the cache and not replace content on a per-request basis. Here’s what that looks like:

vcl 4.1;

import rers;

sub vcl_init {
	new re_cache = rers.init(100);
}

sub vcl_backend_response {
    re_cache.replace_resp_body("Welcome (\w+)!", "Welcome to my website!");
    set beresp.filters = "rers";
}

Keep in mind that set resp.filters = "rers"; becomes set beresp.filters = "rers";.

More information about vmod-rers is available on the corresponding GitHub repository.

vmod-uuid

The uuid VMOD generates uuids that are RFC 4122 compliant.

Here’s a simple VCL example of a uuid that is generated with vmod-uuid:

vcl 4.1;

import uuid;

sub vcl_recv {
    if(!req.http.x-session-id) {
        set req.http.x-session-id = + uuid.uuid();
    }
}

vmod-uuid also has separate methods for specific versions of the uuid specification. More information about vmod-rers is available on the corresponding GitHub repository.