Configuration: Handle upstream server's limited lifetime

Origin configuration

Most popular proxy cache server such as Nginx or Varnish Cache do not support the Sunset header by default. Therefore, additional configuration is required in Unified Origin to generate the Expires or Cache-Control headers responses. In the following sections we describe how to create these configurations.

Note

Cache-Control takes precedence over Expires HTTP header.

Apache

You can generate the Expires response header dynamically based on the Sunset header value. This can be achieved by adding the following LocationMatch directive which copies the Sunset value to the Expires header:

# Create Expires header from Sunset header if matches the specific
# Sunset date format example: `Tue, 08 Mar 2022 14:42:47 GMT`.
<LocationMatch ".*\.(?i:isml)">
  Header setifempty Expires "expr=%{resp:Sunset}" \
    "expr=%{resp:Sunset} =~ m#^[a-zA-Z]+,\s[0-9]{0,2}\s[a-zA-Z]+\s[0-9]{0,4}\s[0-9]{0,2}:[0-9]{0,2}:[0-9]{0,2}\sGMT$#"
</LocationMatch>

Origin shield configuration

Nginx

Nginx reads by default the Expires header. If the Expires header was created based on the Sunset header as previously explained, the object will stay in cache only for the duration of the archive length (--archive_length). Therefore, if you require an Origin shield cache or the CDN to keep the object for a longer period you may need to configure your cache control headers differently.

Note

Nginx sets the cache TTL on objects based on the following precedence:

            # Higher priority ---->  Lower priority
X-Accel-Expires -> Cache-Control -> Expires -> proxy_cache_valid

Varnish Cache

Varnish Cache can be configured to generate the Expires and Cache-Control headers based on the Sunset header. The following VCL snippet is an example of how to generate this behavior.

import std;

sub vcl_backend_response {
    # Set the object's TTL by using Sunset header if Cache-Control=max-age"..."
    # and Expires not found.
    if(beresp.http.Cache-Control !~ "max-age"
       && !beresp.http.Expires &&  bereq.url ~ ".*.[m3u8|m4s|mpd|dash]")
    {
        if(beresp.http.Sunset)
        {
            #  beresp.ttl -> delta time between Sunset and now
            set beresp.ttl = std.time(beresp.http.Sunset, now) - now;
            set beresp.http.x-max-age = beresp.ttl;
            # We round to an integer the max-age value in seconds
            # to comply with [RFC7234] and set Cache-Control: max-age='...'
            set beresp.http.x-max-age = std.integer(beresp.http.x-max-age, 0);
            set beresp.http.Cache-Control = "max-age=" + beresp.http.x-max-age;
            # Remove x-max-age header from response
            unset beresp.http.x-max-age;

            # Add Expires header equals to Sunset header
            set beresp.http.Expires = beresp.http.Sunset;
        }
    }
    # Otherwise use Cache-Control header from backend
    else{
        if(beresp.http.Cache-Control)
        {
            std.log("Use default Cache-Control Header from backend");
        }
        if(beresp.http.Expires)
        {
            std.log("Use default Expires Header from backend");
        }
    }
}