Hide menu Last updated: Feb 09 2017
Area: Episerver DXC Service Applies to versions: Not applicable

CDN recommendations

This topic describes how CDN is used within the Episerver Digital Experience Cloud services, and provides general recommendations for how to configure caching specifically for CDN environments.

How it works

The purpose with a content delivery network or content distribution network (CDN) is to ensure high availability when serving content to visitors. CDN consists of a globally distributed network of proxy servers deployed in multiple data centers. CDNs will deliver content from the fastest and closest server available. 

The CDN has its own URL pointing to the original URL. The visitor will navigate to something like "www.customer.com". The request will go to the CDN, which in turn goes to the origin URL for non-cached data. The request will return to the CDN, which will cache the content. 

By reducing the number of server requests to geographically dispersed locations, more requests can be managed and provided from edge servers closest to the visitor location, resulting in a faster browsing experience. The cache hit ratio describes the percentage of requests the CDN could answer from its own cache.

The CDN stores a copy of your objects, and upon request objects will be served from these caches. The CDN servers are designed to cache content according to the cache rules you define in the HTTP cache headers for your web application. It is critical that these caching rules are correctly set in order for your solution to scale properly.

CDNs and web applications

Setting up a CDN is fairly easy, and even with minor configuration work you can get better performance. It is recommended to develop your application with the CDN in mind from start, and add proper cache headers based on what you want to achieve. This way when you hook up the CDN, it will work automatically.

It is preferable to control the cache settings in the web application rather than writing overriding rules in the CDN, as this can quickly get quite complex. However, there may be situations where rules are needed, for example if special configurations are required, or if you do not want to do a deployment with these changes.

General recommendations

Static content

It is important to evaluate if frequently requested objects can be cached. Static objects can be stored indefinitely in the caches. For cloud-based solutions, it is recommended to make sure that resources like static and resized images, Javascript and CSS files, and scripts, are cached by the intermediary proxies such as those provided by a CDN.

In most cases you can include a version identifier in the path to the resources. If an object changes, the version identifyer updates the URL to it, and the change is immediately reflected. The best way to control the cache for assets is to use unique file names for every deployment. Example: site-1.0.css in the first deploy, and site-1.1.css in the second deploy. This ensures you have the latest CSS file used by the CDN right after deploy.

If for some reason you cannot use version identifiers for frequently requested objects, you can set a maximum lifespan for an object. This is one of the values that are typically set in the cache-control described below. Priority should be version identifier+indefinite caching first, and no version identifier+maximum lifespan second

ETags

The ETag or entity tag is part of HTTP protocol. It is added automatically by IIS and is used for web cache validation. Since you cannot use ETags with DXC Service, it is best to disable or remove them from your solution. To disable ETag headers from the HTTP response, add a setEtag="false" attribute setting to the web.config file under the application root directory.

Example: Disabling ETags.

<configuration>
  ...
<system.webServer>
...
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" setEtag="false" />
</staticContent>
...
</system.webServer>
...
</configuration>

Configuring cache headers

Using the correct cache headers in your application ensures you get the most out of the CDN service, regardless of whether you want to just cache static content, or text/HTML. There are many HTTP header settings, but cache-control is one of the most important ones. This setting defines the time for which a cached object should remain cached. 

A CDN listens to the cache headers in the response settings:

  • If the response has the setting cache-control: no-cache, then the CDN will not cache the content.
  • If the response has the setting cache-control: public, then the CDN caches the content. Note that cache-control must be set to public (not private, as this means that only the browser is allowed to cache the content).

Typical values:

  • max-age=$seconds - determines the lifespan for an object.
  • must-revalidate - tells the cache to strictly follow maximum lifespan information.
  • public - allowed to be cached by intermediaries.
  • private - can be cached, but only by the browser.

Note: Setting cache to public on page requests is not recommended if the page has private information, like a cart page in e-commerce.

Simple cache-control setting

Example: Caching an object for a maximum of 20 minutes.

Cache-Control: public, max-age=1200, must-revalidate

Caching of static content

Use as long max-age as possible, at least for static content, to minimize the trips to the web server. In web.config there are specific sections for setting cache headers for static content. An example of settings can be seen when you install an Episerver site through Visual Studio.

The tag <staticContent> and the subtag <clientCache> set cache headers in the HTTP response. In the example below, static files will be cached for 1 day.

The <caching> tag and its subsettings controls the IIS cache, that is what is cached in the web server by IIS. This will not interfere with the cache headers in the HTTP response, so removing the <caching> tag will not make a difference to the cache in the CDN.

Example: Configuring cache headers for static content.

<configuration>
   <system.webServer>
      <staticContent>
         <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
      </staticContent>
      <caching>
         <profiles>
            <add extension=".gif" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
            <add extension=".png" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
            <add extension=".js" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
            <add extension=".css" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
            <add extension=".jpg" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
            <add extension=".jpeg" policy="DontCache" kernelCachePolicy="CacheUntilChange"/>
         </profiles>
      </caching>
   </system.webServer>
</configuration>

Overriding SetCachePolicy

If you use SetMaxAge, this will set Cache-Control to public, max-age: 60. If you use SetExpires, this will set Cache-Control to public, and Expires to your selected date and time.

Example: Overriding SetCachePolicy.

public abstract class StartTemplatePage<T> : TemplatePage<T> where T : StartPageData
{
   protected override void SetCachePolicy()
   {
      Response.Cache.SetCacheability(HttpCacheability.Public);      // Either use SetMaxAge...
      Response.Cache.SetMaxAge(new TimeSpan(0,1,0)); // One hour      // ... Or SetExpires
      Response.Cache.SetExpires(DateTime.Now.AddSeconds(3600)); // One hour
   }
}

Related topics

Comments