Getting started
Basics
Domains & Origins
Performance

Configuration
Basics
Conditions
Dictionaries
Domains & Origins
Request settings
Cache settings
Headers
Responses
Performance
Purging
Custom VCL
Image optimization
Video

Security
Access Control Lists
Monitoring and testing
Securing communications
Security measures
TLS
Web Application Firewall

Integrations
Logging endpoints
Non-Fastly services

Diagnostics
Streaming logs
Debugging techniques
Common errors

Account info
Account management
Billing
User access and control

Reference

    Image optimization VCL boilerplate

      Last updated July 02, 2019

    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.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    
    sub vcl_recv {
    #FASTLY recv
      if (req.method != "HEAD" && req.method != "GET" && req.method != "FASTLYPURGE") {
        return(pass);
      }
    
      # Enable IO for image file-types
      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 headers which reduce cacheability for images
      if (req.http.X-Fastly-Imageopto-Api) {
        unset beresp.http.Set-Cookie;
        unset beresp.http.Vary;
      }
    
      # Check origin caching headers and override / apply defaults
      if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
        # Keep origin TTL
    
      } else {
        # Apply a default where origin does not provide TTL
        if (beresp.status == 200) {
          set beresp.ttl = 604800s; # 7 days
          set beresp.http.Cache-Control = "max-age=604800, public";
    
          # Apply a longer default TTL for images
          if (req.http.X-Fastly-Imageopto-Api) {
            set beresp.ttl = 2592000s; # 30 days
            set beresp.http.Cache-Control = "max-age=2592000, public";
          }
    
        } else {
          # Apply short TTL for non-200 responses
          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.

    1
    2
    3
    4
    5
    6
    
    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:

    1
    2
    3
    4
    5
    6
    
    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 assets 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:

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

    With query string passthrough enabled, the following will occur:

    1
    2
    3
    
    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:

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

    Default TTL

    The standard Fastly VCL boilerplate applies a default TTL of 3600s. Ideally, image content should have a greater longevity. 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 reprocessing and therefore increased miss latency.

    Back to Top

    Additional resources: