Varnish has a great configuration system. Most other systems use configuration directives, where you basically turn on and off lots of switches. Varnish uses a domain specific language called Varnish Configuration Language, or VCL for short. Varnish translates this configuration into binary code which is then executed when requests arrive.
The VCL files are divided into subroutines. The different subroutines are executed at different times. One is executed when we get the request, another when files are fetched from the backend server.
Varnish will execute these subroutines of code at different stages of its work. Because it is code it is execute line by line precedence isn’t a problem. At some point you call an action in this subroutine and then the execution of the subroutine stops.
If you don’t call an action in your subroutine and it reaches the end Varnish will execute some built in VCL code. You will see this VCL code commented out in default.vcl.
99% of all the changes you’ll need to do will be done in two of these subroutines. vcl_recv and vcl_fetch.
vcl_recv (yes, we’re skimpy with characters, it’s Unix) is called at the beginning of a request, after the complete request has been received and parsed. Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
In vcl_recv you can also alter the request. Typically you can alter the cookies and add and remove request headers.
Note that in vcl_recv only the request object, req is available.
vcl_fetch is called after a document has been successfully retrieved from the backend. Normal tasks her are to alter the response headers, trigger ESI processing, try alternate backend servers in case the request failed.
In vcl_fetch you still have the request object, req, available. There is also a backend response, beresp. beresp will contain the HTTP headers from the backend.
The most common actions to call are these:
In VCL, there are three important data structures. The request, coming from the client, the response coming from the backend server and the object, stored in cache.
In VCL you should know the following structures.
The following operators are available in VCL. See the examples further down for, uhm, examples.
Lets say we want to remove the cookie for all objects in the /static directory of our web server::
sub vcl_recv {
if (req.url ~ "^/images") {
unset req.http.cookie;
}
}
Now, when the request is handled to the backend server there will be no cookie header. The interesting line is the one with the if-statement. It matches the URL, taken from the request object, and matches it against the regular expression. Note the match operator. If it matches the Cookie: header of the request is unset (deleted).
Here we override the TTL of a object comming from the backend if it matches certain criteria::
sub vcl_fetch {
if (req.url ~ "\.(png|gif|jpg)$") {
unset beresp.http.set-cookie;
set beresp.ttl = 3600s;
}
}
You create a named access control list with the acl keyword. You can match the IP address of the client against an ACL with the match operator.:
# Who is allowed to purge....
acl local {
"localhost";
"192.168.1.0"/24; /* and everyone on the local network */
! "192.168.1.23"; /* except for the dialin router */
}
sub vcl_recv {
if (req.request == "PURGE") {
if (client.ip ~ local) {
return(lookup);
}
}
}
sub vcl_hit {
if (req.request == "PURGE") {
set obj.ttl = 0s;
error 200 "Purged.";
}
}
sub vcl_miss {
if (req.request == "PURGE") {
error 404 "Not in cache.";
}
}