-
Guides
- Fastly Status
Mixing and matching Fastly VCL with custom VCL
Last updated October 20, 2017
IMPORTANT: The ability to upload custom VCL code is disabled by default when you sign up. To enable this ability for your account, contact support@fastly.com and request it.
Fastly Varnish syntax is specifically compatible with Varnish 2.1.5. We run a custom version with added functionality and our VCL parser has its own pre-processor. To mix and match Fastly VCL with your custom VCL successfully, remember the following:
- You can only restart Varnish requests three times. This limit exists to prevent infinite loops.
- VCL doesn't take kindly to Windows newlines (line breaks). It's best to avoid them entirely.
- It's best to use
curl -X PURGE
to initiate purges via API. To restrict access to purging, check for theFASTLYPURGE
method not thePURGE
method. When you send a request to Varnish to initiate a purge, the HTTP method that you use is "PURGE", but it has already been changed to "FASTLYPURGE" by the time your VCL runs that request. - If you override TTLs with custom VCL, your default TTL set in the configuration will not be honored and the expected behavior may change.
Inserting custom VCL in Fastly's VCL boilerplate
DANGER: Include all of the Fastly VCL boilerplate as a template in your custom VCL file, especially the VCL macro lines (they start with #FASTLY
). VCL macros expand the code into generated VCL. Add your custom code in between the different sections as shown in the example unless you specifically intend to override the VCL at that point.
Custom VCL placement example
sub vcl_miss {
# my custom code
if (req.http.User-Agent ~ "Googlebot") {
set req.backend = F_special_google_backend;
}
#FASTLY miss
return(fetch);
}
Fastly's VCL boilerplate
sub vcl_recv {
#FASTLY recv
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
return(lookup);
}
sub vcl_fetch {
#FASTLY fetch
if ((beresp.status == 500 || beresp.status == 503) && req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) {
restart;
}
if (req.restarts > 0) {
set beresp.http.Fastly-Restarts = req.restarts;
}
if (beresp.http.Set-Cookie) {
set req.http.Fastly-Cachetype = "SETCOOKIE";
return(pass);
}
if (beresp.http.Cache-Control ~ "private") {
set req.http.Fastly-Cachetype = "PRIVATE";
return(pass);
}
if (beresp.status == 500 || beresp.status == 503) {
set req.http.Fastly-Cachetype = "ERROR";
set beresp.ttl = 1s;
set beresp.grace = 5s;
return(deliver);
}
if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
# keep the ttl here
} else {
# apply the default ttl
set beresp.ttl = 3600s;
}
return(deliver);
}
sub vcl_hit {
#FASTLY hit
if (!obj.cacheable) {
return(pass);
}
return(deliver);
}
sub vcl_miss {
#FASTLY miss
return(fetch);
}
sub vcl_deliver {
#FASTLY deliver
return(deliver);
}
sub vcl_error {
#FASTLY error
}
sub vcl_pass {
#FASTLY pass
}
sub vcl_log {
#FASTLY log
}