Table of Contents
CloudFront for Ruby on Rails
Fast site delivery with Amazon Cloudfront for Ruby on Rails apps
joshcrews.com leanpub.com/cloudfront_rails
What is CloudFront?
Amazon’s (Web Services) CDN
What is a CDN?
Content Delivery Network
A network for serving static files fast.
What problems can it solve?
- Unburden your webserver
- Lower hosting costs
- Speed up your site delivery
Unburden your webserver
If a CDN takes over delivering your assets (js, css, image files), then your server only has to deliver the html pages.
ESPECIALLY IMPORTANT FOR HEROKU
Heroku does not cache/proxy your static assets like many other Rails app hosts do. Heroku users will find the steps in this guide the best single step you can take to speed up your app and lower your dyno’s needed
Lower hosting costs (maybe)
You will need less servers, because they don’t have to serve assets.
You will need less bandwidth from your hosting service, because you aren’t serving assets. If your webhost charges less than $0.12 / GB.
Speed up your site delivery
Page responses will be faster from your unburdened server. Assets will be delivered faster from CloudFront’s speed at delivering static content
Why have a fast site?
Visitors expect instant page loads
- 1 second is tolerable, but slow
- 2 seconds is uhh…
- 3 seconds is Back button
Why have a fast site?
- Facebook pages that are 500ms slower result in a 3% drop-off in traffic, 1000ms is 6% drop-off
- If Amazon increased page load time by +100ms they lose 1% of sales
- If Google increased page load by +500 ms they get 25% fewer searches
- If Yahoo increased page load times by +400ms they see a 5 – 9% drop in full-page traffic
- If Firefox reduced load times by 2.2 seconds they saw an increase in download conversions by 15.4%
Source: http://www.guypo.com/business/17-statistics-to-sell-web-performance-optimization/
Offload serving assets to CloudFront
- It’s easy
- It’s cheap
- asset_sync no longer necessary
If you are using asset_sync gem
If you have never heard of asset_sync, just skip reading to “Preparing your Rails app for CloudFront”.
The asset_sync gem is no longer necessary to server your assets from CloudFront. asset_sync was awesome, but that was before CloudFront could pull your assets directly off your server. The role asset_sync served was to upload all your assets to an S3 bucket, so that CloudFront could connect to S3 and serve your assets. As CloudFront does not need an S3 bucket to serve assets, asset_sync is no longer needed and adds unnecessary code, app maintenance, and deployment steps.
Preparing your Rails app for CloudFront
Is your Rails app ready to use CloudFront? Here’s the steps:
- Rails 3.1+
- serve static assets
- image_tag
- image-url
Rails 3.1+
This book assumes at least Rails 3.1, when the asset pipeline is introduced. The asset pipeline makes it super easy to switch the url that all your assets come from with one line of code. If you can’t upgrade, your road to using CloudFront will be harder.
serve static assets
For Rails apps using heroku (a application hosting service)
in config/produciton.rb
1
config
.
serve_static_assets
=
true
Why?
Most non-heroku apps are served with Apache or Nginx serving the static assets, so Rails doesn’t even get “turned on” for those files. But on heroku, Rails needs to be “turned on” for handling static files.
image_tag
replace
1
<
img
src
=
"/assets/logo.png"
>
with
1
<%=
image_tag
"logo.png"
%>
Why?
image_tag
intelligent points the url to an image asset based on the and the asset_host
setting.
image_tag
will turn <%= image_tag "logo.png" %>
into
<img src="/assets/logo.png"
without as asset_host
defined. But
<img src="http://asset-server.example.com/assets/logo.png"
if we set asset_host
to “http://asset-server.example.com”
image-url
replace
1
background
:
url
(
/assets/
bg
.
jpg
)
with
1
background
:
image
-
url
(
"bg.jpg"
)
image-url, rename css to css.scss
rename styles.css to styles.css.scss anywhere `image-url is used
Why?
url(/assets/bg.jpg)
hardcodes that background image to a relative path, and we need the path to bg.jpg
to change to CloudFront in production.
image-url
is not valid css, but it is valid scss.
What is scss?
SCSS is a “CSS with bonus features” language that compiles down to CSS. Rails will automatically compile styles.css.scss
into styles.css
. One of the features of scss is that it will take
image-url("bg.jpg")
and create url("http://asset-server.example.com/assets/bg.jpg")
in your final css based on the value of asset_host
in your config/(development|test|production).rb file.
All valid css files are valid scss files. So you can add .scss to any css file, and
What about sass?
If you are using sass, great, image-url
works there too.
font-url
If you have font files in your app/assets/fonts
directory, you can use font-url
inplace of url
in scss files and Rails will build the full path to your font files automatically.
Rails app now prepared for CloudFront
test it out (development)
Your site should still look right on localhost:3000
test it out
run
rake assets:precompile RAILS_ENV=production
(You are seeing if any errors are thrown)
That step will write a bunch of files to public/assets
in your project directory. Unless you are intentially precompiling assets locally before every deploy to production, delete that folder.
Deploy your app
Deploy your app to production (or staging)
Does your site look right? If so, you are ready to go.
Setup CloudFront
- signup http://aws.amazon.com
- create a CloudFront distribution
Sign up for AWS
You will have to put down a credit card.
I recommend you do not use your existing Amazon consumer/shopping account. Keep AWS and Amazon shopping separate.
Free AWS allowances
As of writing (June 5, 2014) AWS offers free tiers for many of their services. For CloudFront they offer 2,000,000 requests (2mil hits to your hosted files) and 50 GB out (~ 500,000 hits to a 100kb image) for new users.
Pricing
Is about $0.12 / GB (as of 2014/06/15). That’s cheap for a CDN. $1 should buy you 80,000 hits to a 100kb image.
I can’t guarantee this in 100% of situations, but the pricing should be no-brainer because every hit to a file on CloudFront is a hit that your webserver didn’t have to process, and your webserver didn’t have to pay for bandwidth to serve.
Create CloudFront Distribution
Choose ‘Web’
Press ‘Create Distribution’
Note your CloudFront Distribution URL
Looks like dxxxxxxxxxxxx.CloudFront.net
… takes ~5 minutes to Deploy
The “Status” column will update to “Deployed” on that screen when it’s ready.
Update your asset_host
update config/production.rb
config.action_controller.asset_host = "http://YOUR-CLOUD-FRONT-SUBDOMAIN.CloudFront.net"
Bonus: Update your asset_host for https
update config/production.rb
1
config
.
action_controller
.
asset_host
=
->
(
source
,
request
=
nil
,
*
_
){
2
if
request
&&
request
.
ssl?
3
"https://YOUR-CLOUD-FRONT-SUBDOMAIN.CloudFront.net"
4
else
5
"http://YOUR-CLOUD-FRONT-SUBDOMAIN.CloudFront.net"
6
end
7
}
Deploy to production
Your assets (css/js/images) should be coming from CloudFront
Understanding what is CloudFront doing
How CloudFront works
- Your app points to
http://WHATEVER.cloudfront.net/assets/logo.png
for the logo image (and css, js, all images) - A visitor requests
assets/logo.png
from CloudFront. - If they are the first request for that file in their geographic region, CloudFront will forward that request to your server, serve the file to the visitor, and the save a cached copy
- Future requests CloudFront will serve it’s cached copy (for 1 year by default)
Updating files on CloudFront
So what if your logo changes? Or more likely your css and js files?
Rails handles this automatically!
asset fingerprints
When Rails precompiles assets, it creates a ‘fingerprint’ for each asset. When that asset changes, the fingerprint changes.
So the link to your logo is not /assets/logo.png
, it’s more like
/assets/logo-67268e8d2b9f2b27e2f141d68ca42478.png
When your app deploy again to production, visitors will request the new file, and because that new file is not cached on CloudFront, CloudFront will retrieve the new file from the server.
Bonus: faster deliver times
Your assets will be served by edge locations worldwide
Imagine a site visitor from northern California
(Without a CDN / CloudFront)
In this example, your app server is in northern Virginia.
For all files served by your server, the request and response travels the country.
With CloudFront installed, all your static files get served from an Edge Location in San Francisco.
All CloudFront locations
CloudFront has locations in the United States, Europe, South Asia, East Asia, South America and Australia.
http://aws.amazon.com/cloudfront/details/#Detailed_Description
The farther away your visitor, the more CloudFront helps site speed
Imagine a visitor to your site/app on mobile in India. The request is going to have to travel along way to get your page, but all the other files on the page can come from a CloudFront edge location in India. Your site will be faster than if all css/js/images had to come from the United States.