Varnish Plus

Introduction

This article will describe a configuration example based on a couple of rather popular VMODs: http and goto. Varnish Plus is shipped with dynamic backend support, which simplifies integration and gives the following benefits when used with the policy engine:

  • Backends do not need to be pre-defined. This means that the VCL configuration does not need to be updated whenever endpoints are added or changed in the policy engine.
  • The VCL configuration will be less comprehensive.
  • Proper support for domain names when referring to backends, which is especially useful in dynamic cloud environments.

Example configuration

vcl 4.0;
import http;
import goto;

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

sub vcl_recv {
    # Prepare and send the policy request
    http.init(0);
	
    http.req_copy_headers(0);
    http.req_unset_header(0, "content-length");
    http.req_unset_header(0, "connection");
    
	http.req_set_method(0, req.method);
    http.req_set_url(0, "http://localhost:8088" + req.url);
	
    http.req_send(0);
    http.resp_wait(0);

    # Reject requests not accepted by the Policy Engine
    if (http.resp_get_status(0) != 200) {
        return(synth(http.resp_get_status(0)));
    }

    # Prepare the backend request
    if (http.resp_get_header(0, "x-upstream-url", "") != "") {
        set req.http.x-upstream-url = http.resp_get_header(0, "x-upstream-url", "");
    }
	
    if (http.resp_get_header(0, "x-upstream-path", "") != "") {
        set req.url = http.resp_get_header(0, "x-upstream-path", "");
    }

    if (http.resp_get_header(0, "x-upstream-preserve-host", "") == "false") {
        # The host header should not be preserved
        set req.http.host = http.resp_get_header(0, "x-upstream-host", "");
    }
}

sub vcl_backend_fetch {
    # Use goto to connect to the backend if we got upstream information
    if (bereq.http.x-upstream-url) {
        set bereq.backend =
            goto.backend(bereq.http.x-upstream-url);
    }
}

sub pe_response_headers {
    # Let the client know about the rate limit
    if (http.resp_get_header(0, "x-ratelimit-limit", "") != "") {
        set resp.http.x-ratelimit-limit =
            http.resp_get_header(0, "x-ratelimit-limit", "");
    }

    if (http.resp_get_header(0, "x-ratelimit-remaining", "") != "") {
        set resp.http.x-ratelimit-remaining =
            http.resp_get_header(0, "x-ratelimit-remaining", "");
    }

    if (http.resp_get_header(0, "x-ratelimit-reset", "") != "") {
        set resp.http.x-ratelimit-reset =
            http.resp_get_header(0, "x-ratelimit-reset", "");
    }

    if (http.resp_get_header(0, "www-authenticate", "") != "") {
        set resp.http.www-authenticate =
            http.resp_get_header(0, "www-authenticate", "");
    }
}

sub vcl_synth {
    call pe_response_headers;
}

sub vcl_deliver {
    call pe_response_headers;
}

Statistics

Varnish Custom Statistics can be used to gather interesting statistics from the policy engine setup. The following VCL configuration can be appended to the configuration above to gather policy engine-specific statistics:

vcl 4.0;
import std;
import http;

sub vcl_recv {

    if (http.resp_get_header(0, "x-endpoint", "") != "") {
        std.log("vcs-key:ENDPOINT/" + http.resp_get_header(0, "x-endpoint", ""));
        std.log("vcs-key:ENDPOINT/" + http.resp_get_header(0, "x-endpoint", "") + "/STATUS/" + http.resp_get_status(0));

        if (http.resp_get_header(0, "x-auth-user", "") != "") {
            std.log("vcs-key:CONSUMER/" + http.resp_get_header(0, "x-auth-user", ""));
            std.log("vcs-key:CONSUMER/" + http.resp_get_header(0, "x-auth-user", "") + "/STATUS/" + http.resp_get_status(0));
            std.log("vcs-key:CONSUMER/" + http.resp_get_header(0, "x-auth-user", "") + "/ENDPOINT/" + http.resp_get_header(0, "x-endpoint", ""));
            std.log("vcs-key:ENDPOINT/" + http.resp_get_header(0, "x-endpoint", "") + "/CONSUMER/" + http.resp_get_header(0, "x-auth-user", ""));
        }
    }
}

These few lines of VCL configuration will produce statistics, such as (but not limited to) the number of requests, time to first byte, request size, response size, backend request size, backend response size and cache miss count - broken down by:

  • consumer overall
  • endpoint overall
  • consumer in each endpoint
  • consumer and each response status code
  • consumer in each endpoint and response status code
  • endpoint and each response status code.

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