Amazon CloudFront CDN on Rails

Published:

There are many benefits to using Content Delivery Networks (CDNs), but complexity of implementation or deployment is typically cited as a disadvantage of their use. Thankfully, for a while now, Amazon’s CloudFront has supported a feature called ‘origin pull’, this is a common feature across different CDN brands and what this effectively does it is creates a mirror from your own hosting - pulling content from your own origin server. This means you don’t have to worry about synchronising your files with the CDN’s storage system (e.g. S3).

The only trouble is, file expiry… or rather how does the CDN know when your file has been updated?

CloudFront has an expiry API, however it’s not instant, it’s not free, and it’ll be a whole lot of additional work to implement. Now that Rails has the asset pipeline, there is a much more elegant solution: let the file paths indicate new versions.

As part of the compilation Rails injects a hashed timestamp into the path, e.g. /assets/application.js may become /assets/1234567890abcdef/application.js, upon deployment, those random strings will change meaning the CDN will pull in the updated file.

Note: Older versions of Rails used timestamps in the query parameters of files e.g. /javascripts/application.js?123456789. Unfortunately many CDNs (including CloudFront) and HTTP accelerators will strip these from the URL so if you’re running a version of Rails before the asset pipeline was implemented, you may need to install something like asset_fingerprint.

Origin Setup

I find it’s best to setup a CNAME to your application first, so in your DNS setup the origin subdomain (e.g. origin.example.com) to point to your app’s main domain (e.g. example.com). You can then update your Rails rails_root/config/environments/production.rb to test this domain is working:

config.action_controller.asset_host = "//origin.example.com"

Note the // prefix, to browsers this indicates they should use the same protocol for the request as the HTML page, so if a user is on the HTTP version of your site, it will connect to http://origin.example.com/ for the files, and on the other hand, if they are connecting over HTTPS, it will connect to https://origin.example.com/.

Before deploying the update, you should update your web server configuration, the official Rails guides site has a guide on how to configure both Apache/Nginx for the asset pipeline.

You should now be able to deploy and verify the origin sub-domain is working.

CDN Setup

Once you’ve verified the origin asset host is working, you can setup the CDN mirror in your CloudFront control panel. When logged in, you’ll need to create a new ‘distribution’:

CDN Distribution Setup

You’ll need to select ‘Custom Origin’ to use your own asset host, rather than S3. Add your subdomain as you defined earlier.

If you want to allow HTTPS connections, you’ll need to select ‘Match Viewer’ as the ‘Protocol Policy’.

Access Setup

In the second step, you simply need to enter your chosen CDN subdomain - this will be setup like your origin except it will point to Amazon’s servers, not your own, in the above example I’ve entered cdn.example.com.

Note: CNAMEs will not work if you require HTTPS support, so in that case, leave the ‘CNAMEs’ field blank.

CDN Distribution Details

You should now see your distribution is being setup (see right). So now we need to update our Rails asset_host. If you require HTTPS you’ll need to use the subdomain provided by Amazon e.g:

config.action_controller.asset_host = "//d1aar6ipvvlxt7.cloudfront.net"

If you don’t need HTTPS, you can use your own subdomain:

config.action_controller.asset_host = "http://cdn.example.com"

Note: in this case, you’ll need to setup this subdomain (cdn.example.com) to point to the subdomain Amazon provided (d1aar6ipvvlxt7.cloudfront.net).

There you have it, your site is now serving ultra-fast static assets from Amazon’s local CDN edge-servers, without the need for any further maintenance from you.