Drupal Cache Strategy with Varnish and Edge CDN on Acquia

The requirement is to cache content for as long as possible, but update promptly when content changes are made in Drupal. 

Note that in this setup I’m using Acquia Edge powered by Cloudflare, but the strategy would be similar for Acquia Edge powered by Akamai.

The objective is to bootstrap Drupal as infrequently as possible, by relying on the Varnish and CDN layers, but always to serve fresh content: Cache pages in Varnish for a long time, but provide a method (Purge) to invalidate Varnish when a content change is made in Drupal. At the CDN layer, the goal is to make sure the current version of a page is delivered to the browser, by checking Varnish frequently to see if a new version is available. This check is a lightweight call to Varnish. If Varnish does not have a new version, the CDN-cached version is delivered.

Drupal Modules:

  • Disable Internal Page Cache (page_cache) module. 
  • Enable Internal Dynamic Page Cache (dynamic_page_cache) module.
  • Enable Acquia Purge (acquia_purge) module (which requires Purge module)
    • Ignore the recommendation to set a cache max-age of a year.
  • Install HTTP Cache Control (http_cache_control) module.

Drupal Performance Settings:

  • At Configuration >> Performance
    • Set Browser cache maximum age (max-age) to 1 minute.
      • 2023-09-01: There is a report that setting max-age to zero causes Drupal to make the page uncacheable, ignoring your s-maxage setting. Looking into this as possibly a bug. Setting it to one minute works as expected.
    • Set Shared cache max age (s-maxage) to one month (or something fairly long, such as a day or a week).

CDN settings:

  • Set a Page Rule in Cloudflare, with:
    • Browser Cache TTL: Respect existing headers
    • Edge Cache TTL: 1 minute (or an acceptable update time, such as 5 minutes)
    • Cache Level: Cache Everything
    • Bypass Cache on Cookie: SSESS.*|SESS.*|NO_CACHE|PERSISTENT_LOGIN_.*
  • Set additional page rules to override for any special cases such as admin paths, etc., as needed.

Explanation:

  • Varnish performs the function that page_cache is intended to serve, so page_cache is not needed, and should be turned off to reduce server resource utilization.
  • The dynamic_page_cache module caches certain non-personalized parts of the site for both anonymous and authenticated users, so this should be enabled.
  • Acquia Purge sends cache invalidation requests to the Varnish layer when content changes are made in Drupal, prompting Varnish to load the new version, even if the s-maxage time hasn’t been reached yet.
  • The http_cache_control module provides a setting for s-maxage, which Varnish and CDN will respect. In combination with Purge, this allows pages to be cached in Varnish for a long time, but updated in Varnish with a new version when Purge sends an invalidation request based on cache tags.
  • There is no method to force invalidation of a site visitor’s local browser cache, so instead we set the browser cache max age very low. The max-age header is respected by local browsers. Setting this to very short prevents a user from seeing an old version of the page from local cache.
  • At the CDN layer, we override the s-maxage value by specifying a short Edge Cache TTL. This causes the CDN to check Varnish frequently for a new version of the page, so that changes in Drupal pushed to Varnish via cache invalidation are reflected promptly in the CDN, as well.
  • The Bypass Cache on Cookie setting bypasses caching for Drupal authenticated visitors.