LOG IN SIGN UP
Documentation

Image optimization VCL boilerplate

  Last updated July 19, 2018

If you use the Fastly Image Optimizer (IO) with custom VCL, you should consider using the IO VCL boilerplate. This boilerplate is specially designed to work with IO. It also fixes several potential issues that can arise when using IO with our default VCL boilerplate.

IO VCL boilerplate

Before using the IO VCL boilerplate, review the Image Optimizer documentation and the instructions in our custom VCL guide.

sub vcl_recv {
#FASTLY recv

  if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
    return(pass);
  }

  # enable IO for image file-types -- if you change this line, you must also change the file-type in vcl_fetch
  if (req.url.ext ~ "(?i)(?:gif|png|jpe?g|webp)")  {
    set req.http.X-Fastly-Imageopto-Api = "fastly";
  }

  return(lookup);
}

sub vcl_fetch {
#FASTLY fetch

  unset beresp.http.Set-Cookie;
  unset beresp.http.Vary;
  unset beresp.http.Expires;

  if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
    # override ttl
    } else {
    # apply a default ttl
    if (beresp.status == 200) {
      set beresp.ttl = 604800s;
      set beresp.http.Cache-Control = "max-age=604800, public";

      # apply a longer ttl for images
      if (req.url.ext ~ "(?i)(?:gif|png|jpe?g|webp)") {
        set beresp.ttl = 2592000s;
      }

    } else {
      set beresp.ttl = 60s;
    }
  }

  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
}

Customizing the IO VCL boilerplate

Read the information in this section before modifying the IO VCL boilerplate.

Shielding

You must use shielding with IO. When a request is received at the edge for a particular variation of an image that isn't cached, the shield passes the request along to the image processors, which pass the request to your origin for the original image. Shielding is important because original images and image variations are cached at the shield. Without shielding enabled, more requests are passed directly to your origin.

Limiting IO passthrough to images

The simplest way to prevent non-image files passing through to IO is to limit application of the header by image file extension.

sub vcl_recv {
  if (req.url.ext ~ "(?i)^(?:gif|png|jpe?g|webp)$" {
    set req.http.X-Fastly-Imageopto-Api = "fastly";
  }
  return(lookup);
}

If the origin doesn't have a file extension or doesn't have valid file extensions, you'll need to determine validity using another method. One common approach is identifying images by path:

sub vcl_recv {
  if (req.url.path ~ "/images/" {
    set req.http.X-Fastly-Imageopto-Api = "fastly";
  }
  return(lookup);
}

Another approach is dedicating the entire service to image assets.

X-Fastly-Imageopto-Api header

The X-Fastly-Imageopto-Api header must be applied unconditionally for IO requests at both edge and shield. We unset this by default to prevent the header from being spoofed. Applying this header at the edge only (wrapping with if (!req.http.Fastly-FF)) can result in unexpected behavior. The cache key is constructed differently based on whether IO is enabled or not, so only applying the header at the edge will create a scenario where the same requests reside under different cache keys at the shield and the edge.

Query string passthrough

By default, any query string parameters which don't exist as part of our IO API are stripped in master vcl_recv to protect your origin. Because additional query string parameters form part of the cache key, for each query string variation, there is an additional branch of image variations.

With query string passthrough disabled (default), the following will occur:

Fastly: ?width=100&something=else
Fastly IO: ?width=100
Origin:  [none]

With query string passthrough enabled, the following will occur:

Fastly: ?width=100&something=else
Fastly IO: ?width=100&something=else
Origin:  ?something=else

Enabling query string passthrough presents an attack vector for your origin. For this reason, query string passthrough is only allowed via explicit opt-in, using the following header:

set req.http.X-Fastly-Imageopto-Api = "fastly; qp=*";

Default TTL

The default VCL boilerplate applies a default TTL of 3600s. Ideally, it should be set to least 604800s for image content. When using IO, there's a more severe consequence for a low TTL. It doesn't just mean a cache invalidation and pull from origin. It also invalidates all image variations which results in a lot of reprocessing, leading to increased miss latency.


Back to Top