AWS

Using Amazon Cloudfront with Drupal

We like to use our own site to experiment with different technologies. CDN's are nothing new, and Metal Toad has projects running on competing systems including Akamai and Level 3. Still, I think Amazon Cloudfront is an interesting offering and I wanted to give it a spin. Here's my review of the service after setting it up with Drupal:


We like to use our own site to experiment with different technologies. CDN's are nothing new, and Metal Toad has projects running on competing systems including Akamai and Level 3. Still, I think Amazon Cloudfront is an interesting offering and I wanted to give it a spin. Here's my review of the service after setting it up with Drupal:

Pros:

  • Easy setup, low-cost, only pay for what you use
  • Support for CNAMES and domain sharding (e.g. static[1234].metaltoad.com)
  • Supports Accept:Byte-Range headers (important for media files)
  • Supports gzip compression (assuming your origin server does the compression)
  • Supports HTTPS
  • Honors cache-control headers
  • Custom HTTP headers are passed through to edge requests (including CORS)

Cons:

  • No global or directory "purge" command - each file must be invalidated individually
  • No custom SSL Certificates, so you can't use CNAMES with HTTPS
  • Fussy about SSL ciphers on the origin server (Cloudfront wasn't compatible with the ciphers configured on our load balancer, so I had to use "http-only" instead of "match-viewer")
  • Only minimal logging, no reports or graphs

Domain sharding

Multiple CNAMES add a little overhead with extra DNS lookups, but increase the number of parallel downloads (browsers impose a per-hostname limit). To minimize upstream bandwidth needed, these domains should be cookie-free. Since I chose subdomains of the site itself, I needed to adjust some cookie settings in Drupal:

  • In settings.php, set $cookie_domain = 'www.metaltoad.com';
  • In the Google Analytics module, set the tracking to "One domain with multiple subdomains"

Thanks to some new alter hooks in Drupal 7, all you need to implement a static file CDN is hook_file_url_alter(). There's an actively maintained CDN module, but in the spirit of inquiry I decided to implement the hook directly.

Module file

/**
 * Implements hook_file_url_alter().
 */
function mymodule_file_url_alter(&$uri) {
  // Route static files to Amazon CloudFront.
  if ($_SERVER['HTTP_HOST'] == 'www.metaltoad.com') {
    if ($GLOBALS['is_https']) {
      // Cloudfront doesn't support custom SSL certs, so we need to use Amazon's.
      $cdn = 'https://abcdef12345.cloudfront.net';
    }
    else {
      // Multiple hostnames to parallelize downloads.
      $shard = crc32($uri) % 4 + 1;
      $cdn = "http://static$shard.metaltoad.com";
    }
    $scheme = file_uri_scheme($uri);
    if ($scheme == 'public') {
      $wrapper = file_stream_wrapper_get_instance_by_scheme('public');
      $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
      $uri = "$cdn/$path";
    }
    else if (!$scheme && strpos($uri, '//') !== 0) {
      $uri = "$cdn/$uri";
    }
  }
}
 
/**
 * Implements hook_boot().
 */
function mymodule_boot() {
  // Make sure Amazon CloudFront doesn't serve dynamic content.
  if (!empty($_SERVER['HTTP_X_AMZ_CF_ID']) && !strstr($_GET['q'], 'files/styles')) {
    header("HTTP/1.0 404 Not Found");
    print '404 Not Found';
    exit();
  }
}
 
/**
 * Implements hook_css_alter().
 */
function mymodule_css_alter(&$css) {
  // Mangle the paths slightly so that drupal_build_css_cache() will generate
  // different keys on HTTPS.  Necessary because CDN URL varies by protocol.
  if ($GLOBALS['is_https']) {
    foreach ($css as $key => $style) {
      if ($style['preprocess'] && $style['type'] == 'file') {
        $css[$key]['data'] = './' . $style['data'];
      }
    }
  }
}

.htaccess

# Set CORS header on static assets for CDN.
<FilesMatch "\.(ttf|otf|eot|woff|css|css\.gz|js|js\.gz)$">
  <IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
  </IfModule>
</FilesMatch>

The HTTPS and sharding support adds a little complexity, but overall the integration is straightforward. I'd recommend Cloudfront to anyone who wants an easy and cost-effective scalability win.

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.