<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Alfa Jango Blog &#187; Web</title>
	<atom:link href="http://www.alfajango.com/blog/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.alfajango.com/blog</link>
	<description>Engineering, Software, and Entrepreneurship</description>
	<lastBuildDate>Thu, 09 Sep 2010 17:52:06 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Caching, Zipping, and (Amazon CloudFront) CDN For A Rails App</title>
		<link>http://www.alfajango.com/blog/caching-zipping-and-cdn-for-a-rails-app/</link>
		<comments>http://www.alfajango.com/blog/caching-zipping-and-cdn-for-a-rails-app/#comments</comments>
		<pubDate>Fri, 18 Jun 2010 21:09:47 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Amazon CloudFront]]></category>
		<category><![CDATA[Amazon S3]]></category>
		<category><![CDATA[assets]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Components]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=447</guid>
		<description><![CDATA[In this article, we're going to speed up our Rails application by up to 75%, simply by optimizing our Rails asset host. We're going to serve our components (stylesheets, javascripts, images, etc.) from a combination of our app's server and Amazon CloudFront (Option A, recommended), or entirely from CloudFront (Option B - easier). ]]></description>
			<content:encoded><![CDATA[<div class="note">
<p>
<em>This is Article #4 of a 4-part series. For a good primer, check out the first two articles listed below. For the reasoning and analysis behind the &#8220;Recommended&#8221; option in this article, check out Part 3, <a href="how-to-combine-gzip-plus-cdn-for-fastest-page-loads/">How to Combine GZip + CDN for Fastest Page Loads</a>. Otherwise, jump right in!</em>
</p>
<ul>
	<li><a href="is-your-site-too-slow-the-importance-of-page-load-speed/">The Importance of Page Load Speed</a></li>
	<li><a href="improve-page-load-speed-by-improving-component-load-speed/">Improve Page Load Speed (by 80%) by Improving Component Load Speed</a></li>
	<li><a href="how-to-combine-gzip-plus-cdn-for-fastest-page-loads/">How to Combine GZip + CDN for Fastest Page Loads</a></li>
	<li><strong>Caching, Zipping, and (Amazon CloudFront) CDN For A Rails App</strong>
<ul>
        <li>Prerequisites
        <ol>
          <li>Cached stylesheets and javascripts</li>
          <li>Creating an Amazon AWS Account</li>
        </ol></li>
	<li>Setup S3 Buckets</li>
	<li>Setup CloudFront Distributions</li>
	<li>Create CNAME records (optional)</li>
	<li>Install Rails S3 Synch Plugin
        <ol>
          <li>Installing AWS-S3 Gem</li>
          <li>Configure S3 Synch Plugin</li>
          <li>Add S3 Synch to Deployment</li>
        </ol></li>
	<li>Option A: Compressible Assets from App Server, Images from CloudFront (recommended)
        <ol>
          <li>Configure Rails Asset Host</li>
          <li>Create A-name Record</li>
          <li>Configure Apache</li>
        </ol></li>
	<li>Option B: Serve Everything from CloudFront (easier, but not recommended)
        <ol>
          <li>Configure Rails Asset Host</li>
          <li>Pre-compile Cached Stylesheet and Javascript File</li>
        </ol></li>
        <li>Conclusion</li>
</ul>
</li>
</ul>
</div>
<h2></h2>
<p>
In this article, we&#8217;re going to speed up our Rails application by up to 75%, simply by optimizing our Rails asset host. We&#8217;re going to serve our components (stylesheets, javascripts, images, etc.) from a combination of our app&#8217;s server and Amazon CloudFront (Option A, recommended), or entirely from CloudFront (Option B &#8211; easier). 
</p><p>
The best option for you may depend on your specific needs, but I&#8217;ll cover both processes below. For a an in-depth analysis of why Option A is recommended over Option B, see the last article in this series, <a href="how-to-combine-gzip-plus-cdn-for-fastest-page-loads/">How to Combine GZip + CDN for Fastest Page Loads</a>.
</p>
<h2>Prerequisites</h2>
<h3>Cached Stylesheets and Javascripts</h3>
<p>
Another way to reduce page load time is to combine all of your components into as few files as possible. In other words, combine all of your stylesheets into a single css file, and likewise with your javascripts. Remember from the last article, that each request takes 50-150ms, not including the response and download time. If you have 10 separate javascripts, this equates to 0.5-1.5 seconds just to request the files (not to mention all the time to download them). If you can combine all of the files into one, that means you need just one request to get the same amount of data.
</p>
<p>
Luckily in Rails, this is easy, simply add <code class="codecolorer rails default"><span class="rails"><span style="color:#ff3333; font-weight:bold;">:cache</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'cached-file-name'</span></span></code> to your <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">stylesheet_link_tag</span></span></code> and <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span></span></code> in your application layout. For example:
</p>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">stylesheet_link_tag</span> <span style="color:#996600;">'reset'</span>, <span style="color:#996600;">'application'</span>, <span style="color:#ff3333; font-weight:bold;">:cache</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'all-app-stylesheets'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#996600;">'jquery'</span>, <span style="color:#996600;">'jquery-ui'</span>, <span style="color:#996600;">'application'</span>, <span style="color:#ff3333; font-weight:bold;">:cache</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'all-app-javascripts'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p>
<p>
Now, as long as the following line is set to true in your environment.rb, or more likely in production.rb, Rails will either load your combined files in the layout, or create and load them if they don&#8217;t already exist.
</p><p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">config.<span style="color:#9900CC;">action_controller</span>.<span style="color:#9900CC;">perform_caching</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span style="color:#0000FF; font-weight:bold;">true</span></div></div>

</p>
<p>
<strong>Simply packing all stylesheets and javascripts into one file each reduced page load time of one of our production applications from 10.1 to 8.3 seconds (an 18% reduction in load time alone).</strong>
</p>
<h3>Creating an Amazon AWS Account</h3>
<p>
If you do not yet have an Amazon AWS account, you will need to create that and enable S3 and CloudFront services. See <a href="http://www.hongkiat.com/blog/amazon-s3-the-beginners-guide/">this writeup on creating and setting up an Amazon S3 account</a>. for helpful instructions.
</p>
<h2>Setup S3 Buckets</h2>
<p>
Once you&#8217;ve signed up for your Amazon AWS account and activated S3 and CloudFront, you&#8217;ll want to setup 4 S3 buckets for your application, using Amazons S3 management console.
</p><p>
We&#8217;re going to setup 4 buckets and CDN distributions because some old browsers still have an artificial limitation that only allow 2 concurrent connections to each domain, meaning our components will take longer to download from Amazon if they can only be downloaded 2 at a time. By creating 4 different domains pointing to 4 different buckets/distributions, we&#8217;re allowing our components to download up to 8 at a time from those browsers that still enforce this limitation.
</p>
<p>
<img src="http://www.alfajango.com/blog/wp-content/uploads/2010/06/amazon-s3-bucket-creation-e1276805768507.jpg" alt="" title="amazon-s3-bucket-creation" width="600" height="307" class="alignnone size-full wp-image-583" />
</p>
<div class="in-depth">
When naming your S3 buckets, avoid using periods if you would like the option of accessing your components directly from S3 over HTTPS. Amazon has a trusted SSL wildcard certificate for *.s3.amazonaws.com. 
<br /><br />
If you name your bucket <em>cdn0.yourapp.com</em>, then your components will have the URL <em>https://cdn0.yourapp.com.s3.amazonaws.com/stylesheet.css</em>. This will give you a warning message saying the connection is not trusted, because the browser treats your bucket name as subdomains (and in this case, <em>com.s3.amazonaws.com</em> would be trusted, but subdomains of that, <em>cdn0.yourapp</em> and <em>yourapp</em> will not).
</div>
<h2>Setup CloudFront Distributions</h2>
<p>
Once your S3 buckets are created, click over to the CloudFront tab and create one distribution for each S3 bucket as shown. You can type any comment to help you quickly identify each distribution.
</p>
<p>
<img src="http://www.alfajango.com/blog/wp-content/uploads/2010/06/amazon-cloudfront-distribution-creation-e1276805828838.jpg" alt="" title="amazon-cloudfront-distribution-creation" width="600" height="390" class="alignnone size-full wp-image-584" />
</p>
<h2>Create CNAME Records (optional)</h2>
<p>
Once you&#8217;ve created your 4 CloudFront distributions, you may create a CNAME record for each distribution. This allows you to serve files from CloudFront using your own asset subdomains, like <em>cdn0.yourapp.com</em>, instead of <em>raNDomString1234.cloudfront.net</em>. We&#8217;ll use the following format of <code class="codecolorer ruby default"><span class="ruby">cdn<span style="color:#006600; font-weight:bold;">%</span>d.<span style="color:#9900CC;">yourapp</span>.<span style="color:#9900CC;">com</span></span></code>, where <code class="codecolorer ruby default"><span class="ruby"><span style="color:#006600; font-weight:bold;">%</span>d</span></code> stands for digits 0-3:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">cdn0.yourapp.com<br />
cdn1.yourapp.com<br />
cdn2.yourapp.com<br />
cdn3.yourapp.com</div></div>

</p><p>
<img src="http://www.alfajango.com/blog/wp-content/uploads/2010/06/amazon-cloudfront-cname-configuration.png" alt="" title="amazon-cloudfront-cname-configuration" width="334" height="557" class="alignnone size-full wp-image-580" />
</p>
<h2>Install Rails S3 Synch Plugin</h2>
<p>
This plugin adds some Capistrano recipes to synch our application&#8217;s <code class="codecolorer text default"><span class="text">public</span></code> directory with our four S3 buckets automatically every time we deploy our app. See <a href="http://spattendesign.com/2007/11/6/synching-your-amazon-s3-asset-host-using-capistrano">Spatten Design&#8217;s documentation</a> for more information. I&#8217;ve made some updates to their original plugin to properly set the Cache-control and Expires headers for our assets on S3, as well as to properly set the Content-encoding header for Gzipped assets.
</p>
<p class="note">Update: I&#8217;ve updated the S3 Synch Plugin further; it can now handle unique S3 buckets for different Rails environments (e.g. one set of buckets for production and another for staging). Be sure to update your synch_s3_asset_host.yml file as shown below.</p>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">.<span style="color:#006600; font-weight:bold;">/</span>script<span style="color:#006600; font-weight:bold;">/</span>plugin install git:<span style="color:#006600; font-weight:bold;">//</span>github.<span style="color:#9900CC;">com</span><span style="color:#006600; font-weight:bold;">/</span>JangoSteve<span style="color:#006600; font-weight:bold;">/</span>synch_s3_asset_host.<span style="color:#9900CC;">git</span></div></div>

</p>
<h3>Installing AWS-S3 Gem</h3>
<p>The synch_s3_asset_host plugin requires the AWS-S3 gem, so add the following to your <code class="codecolorer ruby default"><span class="ruby">environment.<span style="color:#9900CC;">rb</span></span></code>:</p>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">&quot;aws-s3&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;aws/s3&quot;</span></div></div>

</p><p>
&#8230;and then run the following from the terminal to install the S3 Synch plugin&#8217;s gem dependency:
</p><p>

<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">sudo</span> rake gems:<span style="color: #c20cb9; font-weight: bold;">install</span></div></div>

</p>
<h3>Configure S3 Synch Plugin</h3>
<p>
Create a <code class="codecolorer text default"><span class="text">config/synch_s3_asset_host.yml</span></code> file like this:
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">AWS_ACCESS_KEY_ID: <span style="color:#996600;">'YOURKEYHERE'</span><br />
AWS_SECRET_ACCESS_KEY: <span style="color:#996600;">'YourSecretAccessKeyHere'</span><br />
production:<br />
&nbsp; asset_host_name: <span style="color:#996600;">&quot;yourapp-com-cdn%d&quot;</span> <span style="color:#008000; font-style:italic;"># This is whatever you named your S3 buckets, using %d in place of the numbers 0-3</span><br />
<span style="color:#008000; font-style:italic;"># dry_run: false # Set to true if you want to test the asset_host uploading without doing anything on Amazon S3</span></div></div>

</p>
<p class="note">Update: The &#8220;production&#8221; part in the file above has been added for my latest update of the S3 Asset Synch Plugin.</p>
<h3>Add S3 Synch to Deployment</h3>
<p>
Now, in your Capistrano <code class="codecolorer text default"><span class="text">deploy.rb</span></code> script, add the following line to the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:deploy</span></span></code> namespace:
</p><p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; ...<br />
&nbsp; <span style="color:#9900CC;">before</span> <span style="color:#996600;">&quot;deploy:symlink&quot;</span>, <span style="color:#996600;">&quot;s3_asset_host:synch_public&quot;</span><br />
&nbsp; ...<br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>

</p><p>
&#8230;and then add the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:asset_host_syncher</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span></span></code> flag to the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:web</span></span></code> role:
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">...<br />
<span style="color:#9900CC;">role</span> <span style="color:#ff3333; font-weight:bold;">:web</span>, <span style="color:#996600;">&quot;yourapp.com&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:asset_host_syncher</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><br />
...</div></div>

</p>
<h2>Option A: Compressible Assets from App Server, Images from CloudFront (recommended)</h2>
<p>
For more detail about why this method is recommended, <a href="how-to-combine-gzip-plus-cdn-for-fastest-page-loads/">see the last article in this series</a>.
</p>
<h3>Configure Rails Asset Host</h3>
<p>
Use the following configuration in your <code class="codecolorer text default"><span class="text">production.rb</span></code> file to configure the way Rails writes the URLs for asset_tags:
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#008000; font-style:italic;"># Enable serving of images, stylesheets, and javascripts from an asset server</span><br />
<span style="color:#008000; font-style:italic;"># config.action_controller.asset_host = &quot;http://assets.example.com&quot;</span><br />
<span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActionController::Base</span></span>.<span style="color:#9900CC;">asset_host</span> = <span style="color:#CC00FF; font-weight:bold;">Proc</span>.<span style="color:#5A0A0A; font-weight:bold;">new</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>source, request<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># the following will route to Amazon S3 + CloudFront if /images asset (setup with CNAMEs as domains cdn0-cdn3)</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># &nbsp; and will route to cdn for anything else (js, css, html), which routes to RMSR's own server so that files can be gzipped and served</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> source.<span style="color:#9900CC;">starts_with</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'/images'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> request.<span style="color:#9900CC;">ssl</span>? <span style="color:#008000; font-style:italic;"># CloudFront does not support HTTPS, but S3 does</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;http://cdn#{source.hash % 4}.yourapp.com&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span> <span style="color:#008000; font-style:italic;"># For SSL we want the certificate to match the hosting domain for cloudfront</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;https://yourcloudfrontdist0.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist1.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist2.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist3.cloudfront.net&quot;</span> <span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span>source.<span style="color:#9900CC;">hash</span> <span style="color:#006600; font-weight:bold;">%</span> 4<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># use the cahed and zipped subdomain for assets that can be zipped (i.e. non-binary filetypes)</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># =&gt; text/html text/css application/x-javascript application/javascript</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}cache.yourapp.com&quot;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#125;</span></div></div>

</p>
<div class="note">
If you did not configure custom CNAME records earlier, your Rails asset_host configuration would be a bit simpler:
<br /><br />

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActionController::Base</span></span>.<span style="color:#9900CC;">asset_host</span> = <span style="color:#CC00FF; font-weight:bold;">Proc</span>.<span style="color:#5A0A0A; font-weight:bold;">new</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>source, request<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> source.<span style="color:#9900CC;">starts_with</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'/images'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist0.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist1.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist2.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist3.cloudfront.net&quot;</span> <span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span>source.<span style="color:#9900CC;">hash</span> <span style="color:#006600; font-weight:bold;">%</span> 4<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># use the cahed and zipped subdomain for assets that can be zipped (i.e. non-binary filetypes)</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># =&gt; text/html text/css application/x-javascript application/javascript</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}cache.yourapp.com&quot;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#125;</span></div></div>

</div>
<div class="in-depth">
Notice the <code class="codecolorer rails default"><span class="rails">source.<span style="color:#9900CC;">hash</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#006666;">4</span></span></code> code above. This ensures that the same component is always served from the same subdomain to take full advantage of client-side caching for that component, rather than randomly selecting from which subdomain to serve each component on each page load.
<br /><br />
For more information on configuring Rails&#8217;s asset_host, <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html">see the documentation for <code class="codecolorer ruby default"><span class="ruby">Base.<span style="color:#9900CC;">asset_host</span></span></code></a>
</div>
<h3>Create A-name Record</h3>
<p>We will also need to create an A-name record for the <i>cache.yourapp.com</i> subdomain, which points to your application server&#8217;s IP address.</p>
<h3>Configure Apache</h3>
<p>
Now we need to configure Apache to accept incoming requests to our &#8220;cache&#8221; subdomain, setting the appropriate far-future Expires and Cache-control headers. We also need to tell Apache to automatically compress and serve any compressible filetype on the fly. Add this to your site&#8217;s Apache <code class="codecolorer text default"><span class="text">conf</span></code> file:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">...<br />
&nbsp; &nbsp;<span style="color: #adadad; font-style: italic;"># gzip html, css, and js</span><br />
&nbsp; &nbsp;<span style="color: #00007f;">AddOutputFilterByType</span> DEFLATE text/html text/css application/x-javascript application/javascript<br />
<br />
&nbsp; &nbsp;&lt;<span style="color: #000000; font-weight:bold;">virtualhost</span> *:80&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #00007f;">ServerName</span> cache.yourapp.com<br />
&nbsp; &nbsp; &nbsp; <span style="color: #00007f;">DocumentRoot</span> /path/to/yourapp/public<br />
&nbsp; &nbsp; &nbsp; &lt;<span style="color: #000000; font-weight:bold;">filesmatch</span> <span style="color: #7f007f;">&quot;.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$&quot;</span>&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #00007f;">ExpiresActive</span> <span style="color: #0000ff;">On</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #00007f;">ExpiresDefault</span> <span style="color: #7f007f;">&quot;access plus 1 year&quot;</span><br />
&nbsp; &nbsp; &nbsp; &lt;/<span style="color: #000000; font-weight:bold;">filesmatch</span>&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #00007f;">FileETag</span> <span style="color: #0000ff;">none</span><br />
&nbsp; &nbsp;&lt;/<span style="color: #000000; font-weight:bold;">virtualhost</span>&gt;<br />
...</div></div>

</p>
<div class="in-depth">
Also note here that we turned off the ETag functionality for this subdomain. ETags (&#8220;entity tags&#8221;) are suppose to be a more flexible mechanism to query and invalidate cached assets, rather than using the last-modified_date of the file. <a href="http://developer.yahoo.com/performance/rules.html#etags">See Yahoo&#8217;s ETag description</a> for more info.
<br /><br />
However, the ETag&#8217;s uniqueness depends not just on the file, but usually on the server it&#8217;s being served from as well. This means if you have your assets copied to several asset domains on different servers, a file downloaded and cached from one server, and then the next page tries to pull the asset from another asset domain, the file&#8217;s ETag will not match the ETag of the cached file, so it will re-download the file instead of serving it from cache.
<br /><br />
Furthermore, Rails does a very good job of appending the last-modified-date to the asset file names (using the asset_tag helpers), which effectively serves, caches, and invalidates the assets for you as necessary. So, we&#8217;re much better off just turning ETags off for our Rails app.
</div>
<p>
Now we need to make sure the appropriate Apache modules are enabled and restart Apache.
</p><p>

<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">sudo</span> a2enmod deflate<br />
<span style="color: #c20cb9; font-weight: bold;">sudo</span> a2enmod expires<br />
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span>apache2 force-reload</div></div>

</p>
<h2>Option B: Serve Everything from CloudFront (easier, but not recommended)</h2>
<p>
For more detail about why this is not recommended, <a href="how-to-combine-gzip-plus-cdn-for-fastest-page-loads/">see the last article in this series</a>. Basically, though, it&#8217;s because it requires you to make one of the following compromises:
</p>
<ul>
<li>a) Serve all files uncompressed, resulting in file sizes up to 4x bigger than necessary.</li>
<li>b) Serve Gzipped assets from CloudFront without first detecting whether or not the visitor&#8217;s browser support Gzip encoding.</li>
</ul>
<p>
That being said, if this is acceptable for you, this method is simpler to set up and configure.
</p>
<h3>Configure Rails Asset Host</h3>
<p>Add the following to your <code class="codecolorer text default"><span class="text">production.rb</span></code>:</p>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActionController::Base</span></span>.<span style="color:#9900CC;">asset_host</span> = <span style="color:#CC00FF; font-weight:bold;">Proc</span>.<span style="color:#5A0A0A; font-weight:bold;">new</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>source, request<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; <span style="color:#008000; font-style:italic;"># Enable serving of images, stylesheets, and javascripts from an asset server</span><br />
&nbsp; <span style="color:#008000; font-style:italic;"># config.action_controller.asset_host = &quot;http://assets.example.com&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> request.<span style="color:#9900CC;">ssl</span>? <span style="color:#008000; font-style:italic;"># CloudFront does not support HTTPS, but S3 does</span><br />
&nbsp; &nbsp; <span style="color:#996600;">&quot;http://cdn#{source.hash % 4}.yourapp.com&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">else</span> <span style="color:#008000; font-style:italic;"># For SSL we want the certificate to match the hosting domain for cloudfront</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;https://yourcloudfrontdist0.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist1.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist2.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;https://yourcloudfrontdist3.cloudfront.net&quot;</span> <span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span>source.<span style="color:#9900CC;">hash</span> <span style="color:#006600; font-weight:bold;">%</span> 4<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></div></div>

</p>
<div class="note">
Again, if you did not configure custom CNAME records earlier, your Rails asset_host will be a bit simpler:
<br /><br />

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActionController::Base</span></span>.<span style="color:#9900CC;">asset_host</span> = <span style="color:#CC00FF; font-weight:bold;">Proc</span>.<span style="color:#5A0A0A; font-weight:bold;">new</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>source, request<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist0.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist1.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist2.cloudfront.net&quot;</span>,<br />
&nbsp; &nbsp; <span style="color:#996600;">&quot;#{request.protocol}yourcloudfrontdist3.cloudfront.net&quot;</span> <span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span>source.<span style="color:#9900CC;">hash</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#006666;">4</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></div></div>

</div>
<h3>Pre-compile Cached Stylesheet and Javascript File</h3>
<p>
If you&#8217;re serving every component from CloudFront, you will need to pre-compile your stylesheets and javascripts on every deploy. Otherwise, Rails will try to compile and save the files to your application server, but try to serve them from S3 (where they won&#8217;t exist).
</p><p>
To solve this, we&#8217;ll add some Capistrano scripts to our <code class="codecolorer text default"><span class="text">deploy.rb</span></code> to compile our files for us before the synch_s3_asset_host plugin copies our <code class="codecolorer text default"><span class="text">public</span></code> directory over to our S3 buckets. But this means, we&#8217;d have to copy the list of asset files to be compiled into our Capistrano script, as well as having them listed in our <code class="codecolorer text default"><span class="text">application.html.erb</span></code> layout. To DRY things up a little, we&#8217;re going to create some project-wide constants:
</p><p>
<code class="codecolorer text default"><span class="text">lib/assets_for_cache.rb</span></code>
</p><p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">module</span> AssetsForCache<br />
&nbsp; &nbsp;JAVASCRIPT_FILES = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'jquery'</span>, <span style="color:#996600;">'jquery-ui'</span>, <span style="color:#996600;">'application'</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp;STYLESHEET_FILES = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'reset'</span>, <span style="color:#996600;">'application'</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp;JAVASCRIPT_CACHE_FILE = <span style="color:#996600;">'all-app-javascripts'</span><br />
&nbsp; &nbsp;STYLESHEET_CACHE_FILE = <span style="color:#996600;">'all-app-stylesheets'</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>

</p><p>
And then replace your <code class="codecolorer ruby default"><span class="ruby">javascript_include_tag</span></code> and <code class="codecolorer text default"><span class="text">stylesheet_link_tag</span></code> in your application layout with the following:
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#6666ff; font-weight:bold;">AssetsForCache::JAVASCRIPT_FILES</span>, <span style="color:#ff3333; font-weight:bold;">:cache</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#6666ff; font-weight:bold;">AssetsForCache::JAVASCRIPT_CACHE_FILE</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">stylesheet_link_tag</span> <span style="color:#6666ff; font-weight:bold;">AssetsForCache::STYLESHEET_FILES</span>, <span style="color:#ff3333; font-weight:bold;">:cache</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#6666ff; font-weight:bold;">AssetsForCache::STYLESHEET_CACHE_FILE</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p><p>
Add this to your deploy.rb script:
</p><p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;height:300px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:assets</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp;<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/../lib/assets_for_cache.rb'</span><br />
&nbsp; &nbsp;set <span style="color:#ff3333; font-weight:bold;">:stylesheets</span>, <span style="color:#6666ff; font-weight:bold;">AssetsForCache::STYLESHEET_FILES</span><br />
&nbsp; &nbsp;set <span style="color:#ff3333; font-weight:bold;">:javascripts</span>, <span style="color:#6666ff; font-weight:bold;">AssetsForCache::JAVASCRIPT_FILES</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;task <span style="color:#ff3333; font-weight:bold;">:package_cached_assets</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; package_stylesheets<br />
&nbsp; &nbsp; &nbsp; package_javascripts<br />
&nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;task <span style="color:#ff3333; font-weight:bold;">:package_stylesheets</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp;sudo <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>rm <span style="color:#006600; font-weight:bold;">-</span>f <span style="color:#008000; font-style:italic;">#{release_path}/public/stylesheets/#{AssetsForCache::STYLESHEET_CACHE_FILE}.css}</span><br />
&nbsp; &nbsp; &nbsp;stylesheets.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>stylesheet<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;run <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>cat <span style="color:#008000; font-style:italic;">#{release_path}/public/stylesheets/#{stylesheet}.css &gt;&gt; \</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color:#008000; font-style:italic;">#{release_path}/public/stylesheets/#{AssetsForCache::STYLESHEET_CACHE_FILE}.css}</span><br />
&nbsp; &nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp;run <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>gzip <span style="color:#006600; font-weight:bold;">-</span>c <span style="color:#008000; font-style:italic;">#{release_path}/public/stylesheets/#{AssetsForCache::STYLESHEET_CACHE_FILE}.css &gt; #{release_path}/public/stylesheets/#{AssetsForCache::STYLESHEET_CACHE_FILE}.css.gz}</span><br />
&nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp;task <span style="color:#ff3333; font-weight:bold;">:package_javascripts</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp;sudo <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>rm <span style="color:#006600; font-weight:bold;">-</span>f <span style="color:#008000; font-style:italic;">#{release_path}/public/javascripts/#{AssetsForCache::JAVASCRIPT_CACHE_FILE}.js}</span><br />
&nbsp; &nbsp; &nbsp;javascripts.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>javascript<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;run <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>cat <span style="color:#008000; font-style:italic;">#{release_path}/public/javascripts/#{javascript}.js &gt;&gt; \</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color:#008000; font-style:italic;">#{release_path}/public/javascripts/#{AssetsForCache::JAVASCRIPT_CACHE_FILE}.js}</span><br />
&nbsp; &nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp;run <span style="color:#006600; font-weight:bold;">%</span><span style="color:#006600; font-weight:bold;">&#123;</span>gzip <span style="color:#006600; font-weight:bold;">-</span>c <span style="color:#008000; font-style:italic;">#{release_path}/public/javascripts/#{AssetsForCache::JAVASCRIPT_CACHE_FILE}.js &gt; #{release_path}/public/javascripts/#{AssetsForCache::JAVASCRIPT_CACHE_FILE}.js.gz}</span><br />
&nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>

</p><p>
&#8230;and then add this to the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:deploy</span></span></code> namespace in your <code class="codecolorer text default"><span class="text">deploy.rb</span></code> file, before calling the s3_asset_host sync script:
</p><p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; ...<br />
&nbsp; <span style="color:#9900CC;">before</span> <span style="color:#996600;">&quot;deploy:symlink&quot;</span>, <span style="color:#996600;">&quot;assets:package_cached_assets&quot;</span><br />
&nbsp; before <span style="color:#996600;">&quot;deploy:symlink&quot;</span>, <span style="color:#996600;">&quot;s3_asset_host:synch_public&quot;</span><br />
&nbsp; ...<br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>

</p>
<h2>Conclusion</h2>
<p>
Now simply save your project and deploy it! The first deploy will take quite a while, as your entire /public directory will be copied to all 4 buckets on Amazon S3, one at a time. But after that, it&#8217;s a painless process. 
</p>
<div class="in-depth">
If you have any files or directories in your public folder that are not assets to be copied to S3 (like a WordPress blog or whatever), you can add them to the <code class="codecolorer text default"><span class="text">--exclude</span></code> list in the synch_s3_asset_host plugin on line 186 of <code class="codecolorer text default"><span class="text">vendor/plugins/synch_s3_asset_host/recipes/synch_s3_asset_host.rb</span></code>
</div>
<p>
Whether you chose the &#8220;recommended&#8221; or the &#8220;easier&#8221; option, you should immediately notice a significant increase in the performance of your Rails app. Thanks for sticking with me through this 4-part series! Please let me know if you have any thoughts, questions, or feedback in the comments.
</p>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/caching-zipping-and-cdn-for-a-rails-app/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>How to Combine GZip + CDN for Fastest Page Loads</title>
		<link>http://www.alfajango.com/blog/how-to-combine-gzip-plus-cdn-for-fastest-page-loads/</link>
		<comments>http://www.alfajango.com/blog/how-to-combine-gzip-plus-cdn-for-fastest-page-loads/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 15:13:46 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Amazon CloudFront]]></category>
		<category><![CDATA[Amazon S3]]></category>
		<category><![CDATA[assets]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[Components]]></category>
		<category><![CDATA[GZipping]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=418</guid>
		<description><![CDATA[For this post, I will discuss how to combine these techniques for the fastest possible asset loading for your site's visitors.  Obviously the ideal setup for serving your assets is to combine all three of these techniques, using a far-out Expires header, zipping text-based assets, and serving them from a CDN.]]></description>
			<content:encoded><![CDATA[<div class="note">
<p>
<em>This is Article #3 of a 4-part series. For a good primer, check out the first two articles listed below. Otherwise, jump right in!</em>
</p>
<ul>
	<li><a href="is-your-site-too-slow-the-importance-of-page-load-speed/">The Importance of Page Load Speed</a></li>
	<li><a href="improve-page-load-speed-by-improving-component-load-speed/">Improve Page Load Speed (by 80%) by Improving Component Load Speed</a></li>
	<li><strong>How to Combine GZip + CDN for Fastest Page Loads
</strong>
<ul>
	<li>Pitfall of Amazon S3 + CloudFront as a CDN: No GZipping</li>
</ul>
<ul>
	<li>Possible Solutions (that don&#8217;t work)
<ul>
	<li>Intercept CloudFront requests with app server and rewrite</li>
	<li>Detect requests with Rails and write asset URLs accordingly</li>
</ul>
</li>
	<li>The Solution: Hybrid Gzipping/CloudFront Depending on Asset-type</li>
</ul>
</li>
</ul>
</div>
<p>
In my last post, I discussed <a href="improve-page-load-speed-by-improving-asset-load-speed">the three techniques used to improve asset load speed</a>. In this post, I will discuss how to combine the use of GZipping and a Content Delivery Network (CDN) for the fastest possible page loads.
</p>
<h2>Pitfall of Amazon S3 + CloudFront</h2>
<p>
Everyone&#8217;s favorite CDN these days is Amazon&#8217;s CloudFront service, which serves files directly from Amazon&#8217;s scalable &#8220;simple storage system&#8221;, Amazon S3. It is very easy to work with, has widespread support in Ruby gems and plugins (and countless other libraries), and is very inexpensive with it&#8217;s pay-as-you-go billing.
</p><p>
However, there is one large pitfall to using Amazon S3 + CloudFront, and that is that neither S3 nor CloudFront support GZip detecting and encoding.  It would seem that we need to now decide whether we&#8217;ll do without GZipping or using a CDN. Not so! There is another way.
</p>
<span id="more-418"></span>
<h2>Possible Solutions (that don&#8217;t work)</h2>
<div class="note">
<em>If you&#8217;re not interested in the solutions that won&#8217;t work, you may <a href="#hybrid-solution">skip straight to the solution that does work</a></em>.
</div><p>
Amazon S3 and CloudFront servers do not detect whether the incoming requests accept GZip encoding, and so they are not able to Gzip and serve components on the fly. Then, it&#8217;s simply a matter of figuring out whether we should link to the compressed or the uncompressed components when the user visits the page.
</p>
<div class="note">
Note that even though Amazon&#8217;s S3 servers cannot GZip and serve GZipped components on the fly, we could still zip our components beforehand and upload the compressed versions to S3 (as long as the Content-encoding header is set to &#8220;gzip&#8221; for the gzipped version being uploaded to S3). Most modern browsers support gzip encoding currently, so this won&#8217;t be a problem most of the time. However, if the user does have a browser that does not support gzip encoding, your site&#8217;s zipped stylesheets and javascripts simply will not work for that user. This may be ok for you. For the rest of this article, though, we will assume this is unacceptable.
</div>
<h3>Detect requests with application and write asset URLs accordingly</h3>
<p>
This solution is similar to the last, except that it attacks the problem one step earlier in the workflow. So, let&#8217;s take a step back. Instead of linking to the asset through our own server, this time, we&#8217;ll revert to linking directly to CloudFront:
</p><p>

<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/link.html"><span style="color: #000000; font-weight: bold;">link</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://xxxxxx.cloudfront.net/stylesheets/application.css&quot;</span> <span style="color: #000066;">media</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;screen&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></div></div>

</p><p>
However, this time we&#8217;ll have our application (whether it be Ruby, PHP, Python, or whatever) detect if the request header accepts GZip encoding, and rewrite the asset tag accordingly.
</p><p>

<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/link.html"><span style="color: #000000; font-weight: bold;">link</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://xxxxxx.cloudfront.net/stylesheets/application.css.gz&quot;</span> <span style="color: #000066;">media</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;screen&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></div></div>

</p><p>
I won&#8217;t go into detail about how to actually accomplish this, because the truth is, this won&#8217;t work either.
</p>
<div class="note">
<em>Edit: As <a href="http://news.ycombinator.com/item?id=1424488">one reader pointed out over on Hacker News</a>, this solution works perfectly fine if your page or site is already uncachable to begin with. In other words, if you cannot cache your site for other reasons, you might as well use this solution.</em>
</div>
<h4>Why this doesn&#8217;t work</h4>
<p>
This will only work as long as your code is run dynamically every time a user loads the page. That means, <strong>once you implement this strategy, you no longer have the option to cache the page</strong>. Ever.
</p><p>
Sure, you could probably come up with some system that creates two versions of each cached page (one with gzipped links and one without), but that will add a lot of complexity to your server setup and filesystem, and it&#8217;s just too much trouble. So, let&#8217;s move on to another solution.
</p>
<h3>Intercept CloudFront requests with app server and rewrite</h3>
<p>
Now this first solution may seem clever, but let&#8217;s see if you can figure out why it won&#8217;t work. The idea here is that rather link to a stylesheet, for example, on CloudFront like this:
</p><p>

<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/link.html"><span style="color: #000000; font-weight: bold;">link</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://xxxxxx.cloudfront.net/stylesheets/application.css&quot;</span> <span style="color: #000066;">media</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;screen&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></div></div>

</p><p>
&#8230;we&#8217;ll instead link to our own server, which will read the request and redirect to either the compressed or the uncompressed stylesheet on CloudFront as appropriate.
</p><p>

<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/link.html"><span style="color: #000000; font-weight: bold;">link</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://compressed.yourdomain.com/stylesheets/application.css&quot;</span> <span style="color: #000066;">media</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;screen&quot;</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></div></div>

</p><p>
And then the Apache configuration for the compressed.yourdomain.com virtual host would look like this:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;<span style="color: #000000; font-weight:bold;">VirtualHost</span> *:80&gt;<br />
&nbsp; <span style="color: #00007f;">ServerName</span> compressed.yourdomain.com<br />
&nbsp; <span style="color: #00007f;">DocumentRoot</span> /home/<span style="color: #00007f;">user</span>/yourapp/current/public<br />
&nbsp; <span style="color: #00007f;">RewriteEngine</span> <span style="color: #0000ff;">On</span><br />
&nbsp; <span style="color: #00007f;">RewriteCond</span> %{HTTP:Accept-Encoding} gzip<br />
&nbsp; <span style="color: #00007f;">RewriteCond</span> %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -s<br />
&nbsp; <span style="color: #00007f;">RewriteRule</span> ^(.+) http://xxxxxx.cloudfront.net$1.gz<br />
&lt;/<span style="color: #000000; font-weight:bold;">VirtualHost</span>&gt;</div></div>

</p>
<div class="in-depth"><em>Note that this particular example first checks if the GZipped file exists on the local filesystem (see <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritecond">Apache&#8217;s RewriteCond docs</a> for more info), then redirects to the GZipped file on CloudFront. So, your local public folder must be sync&#8217;d with S3/CloudFront for this to work.</em></div>

<h4>Why this doesn&#8217;t work</h4>
<p>
Remember in the last article, one of the added benefits of off-loading your assets to a CDN is that your server no longer must listen for and respond to asset requests. This solution rescinds that benefit; even though the asset download still takes place between the CDN server and the user&#8217;s browser, the initial request must still go through your server to be resolved to the CDN.
</p><p>
Furthermore, each component request now requires two DNS lookups instead of one, which adds to the request latency (though the request is latency is small compared to the download time in the request/download cycle).
</p><p>
But the real reason this won&#8217;t work well is because it disrupts the magic that make CDNs fast. A CDN is beneficial primarily because serves files faster by choosing, for each request, the server (or &#8220;service node&#8221;) that is closest in proximity to the user. CDNs are able to estimate the closest server in the CDN using a variety of techniques, including <a title="Reactive probing (page does not exist)" href="/w/index.php?title=Reactive_probing&amp;action=edit&amp;redlink=1">reactive probing</a>, <a title="Proactive probing (page does not exist)" href="/w/index.php?title=Proactive_probing&amp;action=edit&amp;redlink=1">proactive probing</a>, and connection monitoring.  (See <a href="http://en.wikipedia.org/wiki/Content_delivery_network#Content_networking_techniques">Content Networking Techniques</a> for more info)
</p><p>
<strong>By inserting your server (acting as a proxy) into the request cycle between the user&#8217;s computer and the CDN, you may cause the CDN to choose a sub-optimal service node for the delivery of content directly to the user</strong>. If the CDN probes the network from the request side, it will most likely choose the edge node location closest to your server rather than to the user&#8217;s computer, completely negating the benefit of using  the CDN in the first place.
</p><p>
To illustrate this point, consider the typical request/download cycle for a javascript file served from your application&#8217;s server:
</p><p>
<img src="http://www.gliffy.com/pubdoc/2140431/L.png"/>
</p>
<div class="in-depth">
In the above chart, note that the majority of the <em>User</em> wait time is on the <em>File Download</em> side of the cycle. The <em>User Request</em> typically carries around 300 bytes of data, while the javascript file being downloaded would typically be anywhere from 10X to 100X (or more) as much data.
</div>
<p>
Below is a simplified diagram of the typical request/response cycle for a javascript file when using a CDN to serve the component.
</p><p>
<img src="http://www.gliffy.com/pubdoc/2141378/L.png"/>
</p>
<div class="in-depth">
Note that the forwarded requests are much &#8220;cheaper&#8221; in terms of response time than the file download, due to the huge difference in the amount of data being transferred. This is why it&#8217;s still much faster to forward a request a few times in order to make the actual file download as efficient as possible.
</div>
<p>
This final diagram depicts the request/response cycle when delivery components through the CDN with your application server acting as a proxy (so that your app server can read the request and tell the CDN whether to serve the unzipped or the zipped component).
</p><p>
<img src="http://www.gliffy.com/pubdoc/2141360/L.png"/>
</p><p>
Notice in the diagram above, the CDN should have chosen the service node closest to the User, so that the javascript file would have less distance to travel and would thus download the fastest. Instead, it chose the node closer to the application server that proxied the request to the CDN.
</p><p>
The graph below compares download times for the user from my server (located in St. Louis, Missouri), from a server in Amazon CloudFront&#8217;s CDN, and from CloudFront with my server acting as a proxy. I performed this comparison from my own computer here in Ann Arbor, MI, while my buddy, <a href="http://github.com/david">Dave Leal</a>, downloaded the file from his computer in Portugal.
</p><p>
<img src="http://www.alfajango.com/blog/wp-content/uploads/2010/06/Picture-31.png" alt="" title="Download Time for Zipped Javascript File" width="560" height="298" class="alignnone size-full wp-image-528" />
</p>
<a name="hybrid-solution">&nbsp;</a>
<h2>The Solution: Hybrid Gzipping/CloudFront Depending on Asset-type</h2>
<p>
At this point, it may seem like we can choose between two alternatives:
<ul>
<li>Move all assets to the Amazon CloudFront and forget about GZipping</li>
<li>Keep components self-hosted and configure our server to detect incoming requests and perform on-the-fly GZipping as appropriate</li>
</ul>
</p><p>
In our last post, we saw that Gzipping our components can compress them down to ~25% of their original size, which means they&#8217;ll transfer 4X faster. And in this post, we see that serving components from Amazon CloudFront can transfer component files ~2X faster*.
</p>
<div class="in-depth">
<em>*This last statement depends entirely upon your CDN and your own server&#8217;s location and capabilities, so you might want to do a little homework and verify the difference in download times for your own setup.</em>
<br /><br />
The following is the simple formula for Download Time. You can see that <em>File Size</em> is directly proportional to <em>Download Time</em> (so reducing <em>File Size</em> by 1/2 reduces <em>Download Time</em> by 1/2). And <em>Download Speed</em> is indirectly proportional to <em>Download Time</em> (so increasing <em>Download Speed</em> by 2 reduces <em>Download Time</em> by 1/2):
<br /><br />
<img src='http://s.wordpress.com/latex.php?latex=Download%20Time%20%3D%20%5Cfrac%7BFile%20Size%7D%7BDownload%20Speed%7D&#038;bg=ffffcc&#038;fg=000000&#038;s=4' alt='Download Time = \frac{File Size}{Download Speed}' title='Download Time = \frac{File Size}{Download Speed}' class='latex' />
</div>
<p>Ideally we&#8217;d be able to do both (and some other more expensive Content Delivery Networks actually will allow you to). But if we must choose, compressible file-types gain much more by way of serving them compressed, than by serving them uncompressed from a CDN edge location. So, we will serve compressible file-types (stylesheets, javascripts, and static HTML files) from our own server, GZipped.
</p><p>
However, images are already compressed in the image encoding; image file size is unaffected by Gzipping them on our server. So, we may as well allow images to benefit from the 2X speed improvement by serving them straight from our Amazon CloudFront CDN.
</p><p>
<strong>Using this solution for hosting/serving components, we&#8217;ve been able to reduce page load time by 75% on several of our sites.</strong>
</p>
<div class="note">
<p>
If you have a Ruby on Rails application, implementing this solution is easy, and won&#8217;t take you more than an hour or so. Stay tuned for Part 4: <em>Caching, Zipping, and (Amazon CloudFront) CDN For A Rails App</em>.
</p>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/how-to-combine-gzip-plus-cdn-for-fastest-page-loads/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Improve Page Load Speed (by 80%) by Improving Component Load Speed</title>
		<link>http://www.alfajango.com/blog/improve-page-load-speed-by-improving-component-load-speed/</link>
		<comments>http://www.alfajango.com/blog/improve-page-load-speed-by-improving-component-load-speed/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 23:00:55 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[asset]]></category>
		<category><![CDATA[component]]></category>
		<category><![CDATA[load time]]></category>
		<category><![CDATA[page speed]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=391</guid>
		<description><![CDATA[80-90% of the end-user response time is spent downloading all the components in the page: images, stylesheets, scripts, Flash, etc. This is the Performance Golden Rule." In other words, you can get the most "bang for your buck" when it comes to page load optimization by speeding up the loading of your site components (a.k.a. "assets", such as javascripts, CSS stylesheets, images, etc.). In this post, I'll discuss the 3 main techniques used to improve asset load speed.]]></description>
			<content:encoded><![CDATA[<div class="note">
<p>
<em>This is Article #2 of a 4-part series. This article (along with Article #1) serves as a primer for the next two entries in this series, which discuss the most efficient way to put these concepts into practice in your web application. For more a more in-depth look at these concepts, see <a href="http://developer.yahoo.com/performance/rules.html">Yahoo!&#8217;s Best Practices for Speeding Up Your Web Site</a> and <a href="http://code.google.com/webtoolkit/speedtracer/">Google&#8217;s Speed Tracer tutorial</a></em>
</p>
<ul>
	<li><a href="is-your-site-too-slow-the-importance-of-page-load-speed/">The Importance of Page Load Speed</a></li>
	<li><strong>Improve Page Load Speed by Improving Asset Load Speed </strong>
<ul>
	<li>3 Techniques to Speed Up Asset Loading
<ul>
	<li>Better Caching with Expires header</li>
	<li>Zipping</li>
	<li>Content Delivery Network (CDN)</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<p>
In my last post, I discussed <a href="is-your-site-too-slow-the-importance-of-page-load-speed/">why it&#8217;s becoming increasingly important to ensure your website loads quickly</a> for users (and Googlebots). At the end of the article, I mentioned a quote from Yahoo!&#8217;s article, <a href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web Site</a>:
</p><p>
<blockquote>80-90% of the end-user response time is spent downloading all the components in the page: images, stylesheets, scripts, Flash, etc. This is the Performance Golden Rule.</blockquote>
</p><p>
In other words, you can get the most &#8220;bang for your buck&#8221; when it comes to page load optimization by speeding up the loading of your site components (a.k.a. &#8220;assets&#8221;, such as javascripts, CSS stylesheets, images, etc.). In this post, I&#8217;ll discuss the 3 main techniques used to improve asset load speed.
</p><p>
Asset load optimization often results in a reduction in asset-load-time by 75-90%. Since asset-load-time accounts for 80-90% of your total page-load-time, this equates to an overall reduction in page-load-time by up to 80%!
</p><p>
Below are graphs showing the load time of RateMyStudentRental.com before and after (respectively) implementing the asset-optimization shown here. Using <a href="http://code.google.com/webtoolkit/speedtracer/">Google&#8217;s Speed Tracer extension</a>, we can see that <strong>total load time decreased from 40 milliseconds down to 15ms</strong>.
</p><p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-8.png"><img title="Page Load Time - Before Asset Optimization" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-8-300x49.png" alt="" width="500" height="82" /></a>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-10.png"><img title="Page Load Time - After Asset Optimization" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-10-300x49.png" alt="" width="500" height="82" /></a>
</p>
<span id="more-391"></span>
<h2>3 Techniques to Speed Up Asset Loading</h2>
<p>
So we know that when a user visits your site, their browser must download your javascripts and CSS stylesheets so that your site will display properly. Luckily this only happens once per session by default, because the user&#8217;s browser will then cache those assets on the user&#8217;s computer. This means that each subsequent page load, as the user navigates through your site, will simply reload the assets from the user&#8217;s computer without needing to download them again. But this isn&#8217;t good enough, we can make it faster.
</p>
<h3>Better Caching with Expires Header</h3>
<p>
Remember when I said the browser will cache assets once per session by default? That&#8217;s not good enough for our purposes. We need to setup our server to explicitly tell users&#8217; browsers to cache assets until further notice.
</p><p>
This is difficult to do reliably across all browsers/environments, so the way we accomplish this is by actually telling users&#8217; browsers to cache everything for a year (or some other arbitrarily long duration). Then Rails&#8217;s built-in asset helpers append timestamps to the asset URLs every time you update and deploy your assets. This fools users&#8217; browsers into thinking they&#8217;re looking at a different asset (since the filename has a different timestamp), which makes the browsers re-download and cache the new files when you deploy updates.
</p>
<div class="in-depth">
<em>It&#8217;s important to note that there are other directives that help control component caching, including the Cache-control Header and Etags that may be used in conjunction with the Expires header. For our purposes, we will simply set Cache-control to &#8220;public&#8221; along with the proper Expires header (and turn Etags off). AskApache.com has<a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html"> a simple writeup on setting these up</a>.</em>
<br /><br />
<em>If you would like to read more about how Apache handles Expires and Cache-control headers, <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html">W3.org has excellent documentation</a>. They also have great <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">documentation on the various Header protocols in general</a>.</em>
</div>
<p>
We&#8217;ve now discussed telling users&#8217; browsers to keep cached versions of our assets for longer than one session. But we still need to speed up that first page visit, by speeding up the user&#8217;s first download of our assets.
</p>
<h3>Zipping</h3>
<p>
Have you ever zipped a file before emailing it to someone in order to make the file-size smaller? Well, most modern browsers actually know how to read a zipped file directly without needing to unzip it. This means that instead of serving full javascript files or CSS stylesheets, you can serve zipped files (often 1/3 or less of the original file-size) and make the page load much faster, since smaller files take less time to download.
</p><p>
<img src="http://www.alfajango.com/blog/wp-content/uploads/2010/06/Picture-24.jpg" alt="" title="JS vs GZipped File-size" width="320" height="199" class="alignnone size-full wp-image-508" />
</p><p>
Even better is that servers, such as Apache, can check if the requesting browser accepts GZip encoding (the standard zipping algorithm), and automatically serve zipped files if accepted. All you have to do is enable it in your server.
</p>
<div class="in-depth">
<em>You should only GZip uncompressed file-types (usually the text-based files, like JS, CSS, and HTML). Technically you can GZip images, but most image encodings (like .jpg, .png, etc.) are already compressed, so it does nothing to the file-size and is an unnecessary load to place on your server.</em>
</div>
<h3>Content Delivery Networks (CDNs)</h3>
<p>
So far, we&#8217;ve discussed making the files stay cached by users&#8217; browsers for longer than one session, and then speeding up the first download by zipping the assets, making their file-sizes smaller. There is still one more thing we can do to make the assets download faster, and that is use a Content Delivery Network, or CDN. A CDN is a group of servers physically scattered all around the world that host and serve copies of your assets for you.
</p><p>
Even though it may seem like data transmission is instantaneous, it still takes time for electrons to travel through wires (even optical networks &#8220;only&#8221; transmit data at the speed of light, which is not instantaneous). Thus, the shorter the distance we need to transmit data, the faster it will be transmitted. If your existing asset server (by default, the server from which your site is hosted) is located in the US, then your assets will download more quickly for me (located in the US) than it will for my buddy, Dave, in Portugal. The purpose of a CDN is to serve your assets on a per-user-basis from the server in the CDN that is physically closest to that user.
</p><p>
Don&#8217;t believe me? Just check out the difference in ping time (the amount of time it takes for a computer to contact the server and for the server to respond) for my buddy, Dave, in Portugal pinging my server in the US compared to pinging a CDN server in Europe.
</p><p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-23.png"><img title="Ping Time from Portugal" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-23.png" alt="" width="500" height="203" /></a>

<div class="in-depth">
<em>It&#8217;s also important to realize that off-loading your page components to a CDN has another very beneficial side-effect. It reduces the stress on your server. Every time a page on your site loads, an additional request is made to your server for every single stylesheet, javascript, and image on the page (if you haven&#8217;t yet implemented proper caching, that is). By moving these files to a separate CDN, your server no longer has to listen for and fulfill component requests. That means one page load equals one request for your server!</em>
</div>
<h2>Putting This Knowledge To Use</h2>
</p><p>
What have we learned here? We&#8217;ve learned that we can reduce download time by reducing the size of the files being downloaded. GZip compression can reduce text-based files to 1/3rd their original size, which reduces download time by 67%. Then we can move assets to a CDN, which can reduce transmission time by another 67%. Doing the math, we see that <strong>component download time is reduced by 90%, which equates to an overall reduction in page load time of 80%</strong>.
</p><p>
Now that we&#8217;ve covered <a href="is-your-site-too-slow-the-importance-of-page-load-speed/">the importance of page load speed</a>, and the 3 techniques used to speed up the loading of assets (or site components), we can figure out how best to combine this knowledge into the optimal configuration, and then finally, how to implement this into our own sites.
</p>
<div class="note">
<p>
Stay tuned for <em>Part 3: <a href="http://www.alfajango.com/blog/optimal-configuration-of-caching-zipping-and-cloudfront-cdn-for-fastest-componen-loading/">Optimal Configuration of Caching, Zipping, and (CloudFront) CDN for Fastest Component Loading</a>.
</em></p>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/improve-page-load-speed-by-improving-component-load-speed/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Is Your Site Too Slow?(The Importance of Page Load Speed)</title>
		<link>http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/</link>
		<comments>http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/#comments</comments>
		<pubDate>Fri, 14 May 2010 20:50:18 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[assets]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[page load speed]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[stylesheets]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=394</guid>
		<description><![CDATA[Page load speed is becoming increasingly important as rich web applications become more interactive. It's not just about usability anymore; it can now directly affect your placement in search engine results, now that Google uses page load speed in their ranking algorithm. Are you ready for a reality check? Get Google Webmaster Tools for your site, and go to the Labs &#62;&#62; Site Performance to view your average page load time, as seen by Google's web crawlers. That's right, Google is already tracking your site's performance history]]></description>
			<content:encoded><![CDATA[<div class="note">
<p>
<em>This is article #1 of a 4-part series. This article (along with Article #2) serves as a primer for the last two entries in this series, which discuss the most efficient way to put these concepts into practice in your web application. For more a more in-depth look at these concepts, see <a href="http://developer.yahoo.com/performance/rules.html">Yahoo!&#8217;s Best Practices for Speeding Up Your Web Site</a> and <a href="http://code.google.com/webtoolkit/speedtracer/">Google&#8217;s Speed Tracer tutorial</a></em>
</p>
</div>
<p>
Page load speed is becoming increasingly important as rich web applications become more interactive. It&#8217;s not just about usability anymore; it can now directly affect your placement in search engine results, now that <a href="http://searchengineland.com/site-speed-googles-next-ranking-factor-29793">Google uses page load speed in their ranking algorithm</a>. Are you ready for a reality check? Get <a href="http://www.google.com/webmasters/tools/">Google Webmaster Tools</a> for your site, and go to the Labs &gt;&gt; Site Performance to view your average page load time, as seen by Google&#8217;s web crawlers. That&#8217;s right, Google is already tracking your site&#8217;s performance history.
</p><p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-4.png"><img title="Picture 4" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-4-300x64.png" alt="" width="500" height="107" /></a>
</p><p>
Google Webmaster Tools is even kind enough to tell you how you stack up against the rest of the web. Here is what Webmaster Tools had to say about one of our sites before optimizing it for quick page loading:
</p><p>
<blockquote>On average, pages in your site take <em>4.5 seconds to load</em> (updated on Feb 21, 2010). This is <em>slower than 70% of sites</em>. These estimates are of <em>low accuracy</em> (fewer than 100 data points). The chart below shows how your site&#8217;s average page load time has changed over the last few months. For your reference, it also shows the 20th percentile value across all sites, separating slow and fast load times.</blockquote>
</p><p>
Ouch. Did I mention this would be a painful reality check?
</p><p>
Now to be fair, there&#8217;s a very reasonable explanation for this. Google claims that the majority of users will click &#8220;back&#8221; to the search results page if a link takes too long to load. So, <strong>if a webpage is too slow for the visitor to read it, the relevance of the content is&#8230;well, irrelevant</strong>. I should point out, however, that it&#8217;s unknown precisely how much page load speed affects your placement in search results.
</p><p>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="500" height="297" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="flashvars" value="&amp;autostart=false&amp;bandwidth=5039&amp;dock=false&amp;file=http%3A%2F%2Fvideos.webpronews.com%2Fvideo%2Fplaylist.php%3Fmovie_name%3Dpubcon09_cutts&amp;linktarget=_self&amp;plugins=yourlytics-1%2Cviral-2&amp;repeat=false&amp;screencolor=0x000000&amp;yourlytics.height=273&amp;yourlytics.visible=true&amp;yourlytics.width=500&amp;yourlytics.x=0&amp;yourlytics.y=0" /><param name="src" value="http://videos.webpronews.com/video/jwplayer/player.swf" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="500" height="297" src="http://videos.webpronews.com/video/jwplayer/player.swf" allowfullscreen="true" flashvars="&amp;autostart=false&amp;bandwidth=5039&amp;dock=false&amp;file=http%3A%2F%2Fvideos.webpronews.com%2Fvideo%2Fplaylist.php%3Fmovie_name%3Dpubcon09_cutts&amp;linktarget=_self&amp;plugins=yourlytics-1%2Cviral-2&amp;repeat=false&amp;screencolor=0x000000&amp;yourlytics.height=273&amp;yourlytics.visible=true&amp;yourlytics.width=500&amp;yourlytics.x=0&amp;yourlytics.y=0"></embed></object>
</p>
<h2>What is Included in Page Load Time?</h2>
<p>
At first, you may think that Google crawlers only index the initial load-time of the HTML. You&#8217;d be wrong. They actually include the time it takes to load all Javascript files, CSS stylesheets, images, etc. Now it&#8217;s time to see how your site performs. For this, you&#8217;ll need either the <a href="http://code.google.com/speed/page-speed/download.html">Page Speed extension for Firefox</a>, or for an even better look into your site&#8217;s performance, get <a href="http://code.google.com/webtoolkit/speedtracer/">Speed Tracer for Chrome</a>. And of course, there&#8217;s always the ever-popular <a href="http://developer.yahoo.com/yslow/">YSlow extension for Firefox</a> from Yahoo!
</p>
<a href='http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/picture-5/' title='Speed Tracer for Chrome'><img width="150" height="150" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-5-150x150.png" class="attachment-thumbnail" alt="" title="Speed Tracer for Chrome" /></a>
<a href='http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/picture-6/' title='Page Speed for Firefox'><img width="150" height="150" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-6-150x150.png" class="attachment-thumbnail" alt="" title="Page Speed for Firefox" /></a>
<a href='http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/picture-7/' title='YSlow for Firefox'><img width="150" height="150" src="http://www.alfajango.com/blog/wp-content/uploads/2010/05/Picture-7-150x150.png" class="attachment-thumbnail" alt="" title="YSlow for Firefox" /></a>

<h2>Watch Your Assets</h2>
<p>
Your website&#8217;s assets include all of the files the visitor&#8217;s browser must download to render your webpage. This includes Javascript files, CSS stylesheets, and images. And <a href="http://developer.yahoo.com/performance/rules.html">according you Yahoo!</a>:
</p><p>
<blockquote>80-90% of the end-user response time is spent downloading all the components in the page: images, stylesheets, scripts, Flash, etc.</blockquote>
</p>
<div class="note">
<p>
<a href="http://www.alfajango.com/blog/improve-page-load-speed-by-improving-component-load-speed/">Continue to Article #2</a>, which focuses on reducing the time it takes visitors to download your site&#8217;s assets by up to 90%. That means your site will load up to 2-3x faster.
</p>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/is-your-site-too-slow-the-importance-of-page-load-speed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Release: jQuery EasyTabs Plugin</title>
		<link>http://www.alfajango.com/blog/new-release-jquery-easytabs-plugin/</link>
		<comments>http://www.alfajango.com/blog/new-release-jquery-easytabs-plugin/#comments</comments>
		<pubDate>Fri, 30 Apr 2010 19:50:10 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Open-source]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[plugins]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=389</guid>
		<description><![CDATA[I recently wrote a lightweight jQuery plugin called EasyTabs, and it is now released on the official jQuery plugin website. Most front-end developers are familiar with the jQuery-UI tab plugin. However, it is a very magical plugin with a complex structure, which completely styles your tabs for you, and limits your options when deciding how to structure the tabbed content.]]></description>
			<content:encoded><![CDATA[<p>
I recently wrote a lightweight jQuery plugin called <a href="http://www.alfajango.com/blog/jquery-easytabs-plugin/">EasyTabs</a>, and it is now released on the official <a href="http://plugins.jquery.com/project/easytabs">jQuery plugin website</a>. Most front-end developers are familiar with the <a href="http://jqueryui.com/demos/tabs/">jQuery-UI tab plugin</a>. However, it is a very magical plugin with a complex structure, which completely styles your tabs for you, and limits your options when deciding how to structure the tabbed content.
</p><p>
For instance, it is very difficult to place your tabs below the tabbed content with jQuery-UI tabs.. You must perform some crazy CSS trickery, because jQuery-UI tabs forces you to place your <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span></span></code> before your content <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></span></code>s. Not to mention all of the jQuery-UI styling it does to your tabs by default, making it difficult to override and apply custom stylization to your tabs.
</p><p>
This new plugin, jQuery EasyTabs, is very flexible for the required markup and structure of your tabs and content. Also, it handles only the functionality of creating in-page tabs, leaving all of the styling up to you and your own CSS.
</p><p>
To check it out, see our <a href="http://www.alfajango.com/blog/jquery-easytabs-plugin/">documentation</a> and <a href="http://www.alfajango.com/blog/jquery-easytabs-plugin/#demos">demos</a>. Then when you&#8217;re ready, you can download it from the <a href="http://plugins.jquery.com/project/easytabs">jQuery plugins website</a>.
</p>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/new-release-jquery-easytabs-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails, Prototype, and JQuery in Harmony (or how to replace Prototype with JQuery)</title>
		<link>http://www.alfajango.com/blog/rails-prototype-to-jquery/</link>
		<comments>http://www.alfajango.com/blog/rails-prototype-to-jquery/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 00:07:09 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[JRails]]></category>
		<category><![CDATA[noConflict]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Scriptaculous]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=262</guid>
		<description><![CDATA[It has become common practice to use JQuery as the javascript library of choice for Ruby on Rails applications. If you have a Rails app already using Prototype, it usually isn't feasible to replace it in one swoop. And sometimes, you just simply need both to work at the same time. Whether you want to use both in unison (not recommended as a long-term strategy), or you want to gradually migrate from Prototype to JQuery, it's not as scary as you may think.]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/04/rails-prototype-jquery.jpg"><img class="size-full wp-image-270 centered" title="rails-prototype-jquery" src="http://www.alfajango.com/blog/wp-content/uploads/2010/04/rails-prototype-jquery.jpg" alt="" width="456" height="292" /></a>
</p>
<p>It has become common practice to use JQuery as the javascript library of choice for Ruby on Rails applications. If you have a Rails app already using Prototype, it usually isn&#8217;t feasible to replace it in one swoop. And sometimes, you just simply need both to work at the same time. Whether you want to use both in unison (not recommended as a long-term strategy), or you want to gradually migrate from Prototype to JQuery, it&#8217;s not as scary as you may think.
</p><p>
The secret is that it is difficult to get Prototype to play nicely with JQuery, while it is rather trivial to get JQuery to play nicely with Prototype. This may seem like a minor distinction, but it is one that will save you a lot of headaches.
</p>
<h2>Use Prototype/Scriptaculous with JQuery</h2>
<p>
First, in our application layout, we&#8217;re going to get rid of <code class="codecolorer rails default"><span class="rails"><span style="color:#006600; font-weight:bold;">&lt;%</span>=<span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#ff3333; font-weight:bold;">:defaults</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></span></code> and include each javascript file explicitly just to make things a little less magicky and a little more straight forward.
</p>
<span id="more-262"></span>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#996600;">'prototype'</span>, <span style="color:#996600;">'scriptaculous'</span>, <span style="color:#996600;">'application'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p><p>
Now, we&#8217;ll add in JQuery (and JQuery UI while we&#8217;re at it, just for fun). You&#8217;ll want to grab the latest release from the <a href="http://docs.jquery.com/Downloading_jQuery#Current_Release">JQuery download page</a> (and the latest <a href="http://jqueryui.com/download">JQuery UI</a> as well).
</p>
<p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#996600;">'prototype'</span>, <span style="color:#996600;">'scriptaculous'</span>, <span style="color:#996600;">'jquery'</span>, <span style="color:#996600;">'jquery-ui'</span>, <span style="color:#996600;">'application'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p><p>
Right under that line, in your Rails application layout, we&#8217;ll insert the one-liner that makes JQuery play nicely with Prototype, YUI, etc.
</p><p>

<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">&lt;</span>script<span style="color: #339933;">&gt;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// this allows jquery to be called along with scriptaculous and YUI without any conflicts</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// the only difference is all jquery functions should be called with $j instead of $</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// e.g. $j('#div_id').stuff instead of $('#div_id').stuff</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> $j <span style="color: #339933;">=</span> jQuery.<span style="color: #660066;">noConflict</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #339933;">&lt;/</span>script<span style="color: #339933;">&gt;</span></div></div>

</p><p>
Try doing this with Prototype (especially if you&#8217;re using other scripts built on top of Prototype and Scriptaculous), and you&#8217;ll soon find yourself pulling out your hair.
</p><p>
If you simply want the ability to use both libraries together in your app, then congratulations, you&#8217;re done. You can now do this:
</p><p>

<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Effect.<span style="color: #660066;">Fade</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'element_id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
$j<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#element_id'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>

</p><p>
Notice the first line uses the Prototype element id selector, <code class="codecolorer javascript default"><span class="javascript">$</span></code> with a Scriptaculous effect, and the second line uses the new noConflict JQuery selector <code class="codecolorer javascript default"><span class="javascript">$j</span></code>.
</p>
<h2>Make Rails Use JQuery Instead of Prototype</h2>
<div class="note">
<em>Update: This is actually even easier now with Rails 3. All you have to do is tell Rails to use the jQuery API javascript file instead of the Prototype API javascript file. See <a href="http://github.com/lleger/Rails-3-jQuery">this Rails3-jQuery project on Github</a> for using jQuery natively with a Rails 3 application.</em>
</div>
<p>
Let&#8217;s assume that we&#8217;d like to phase Prototype out of our app in favor of JQuery. In addition to going through your application and replacing all of your Prototype code with JQuery code, you&#8217;ll need to take care of the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html">Rails Prototype helper magic</a> (note that when Rails 3 becomes the standard, this won&#8217;t be necessary).
</p><p>
This is really easy, thanks to the <a href="http://mirror.ozdiy.com/assets/b8/2f96a12bc919b37e09d303b86ea1b9_1251811910.html">JRails plugin</a>, which can be <a href="http://github.com/aaronchi/jrails">found on Github</a>. Install it in your Rails project from your root directory.
</p><p>

<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">.script<span style="color: #000000; font-weight: bold;">/</span>plugin <span style="color: #c20cb9; font-weight: bold;">install</span> git:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>aaronchi<span style="color: #000000; font-weight: bold;">/</span>jrails.git</div></div>

</p><p>
Now, your Rails helpers, such as <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">link_to_remote</span></span></code>, <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">form_remote_tag</span></span></code>, etc. are using JQuery to build the AJAX code instead of Prototype on the back end. Isn&#8217;t Rails magic neat?
</p>
<h2>Caveat: Delayed Observer</h2>
<div class="note">
<em>Update: If you are trying to get delayed observer to work with jQuery in a Rails 3 application, <a href="http://www.alfajango.com/blog/rails-prototype-to-jquery/#comment-2763">see my comment below</a>.</em></div>
<p>
There is one more step if you&#8217;re using the <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">observe_form</span></span></code> helper method. This helper relies on Prototype&#8217;s <code class="codecolorer javascript default"><span class="javascript">Element.<span style="color: #660066;">observe</span></span></code> method, which does not exist in the standard JQuery library.
</p><p>
No worries, someone has done the work for you already (not me). Just download and include the <a href="http://code.google.com/p/jquery-utils/wiki/DelayedObserver">JQuery delayed observer plugin</a> in your layout, and you&#8217;re all set.
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#996600;">'prototype'</span>, <span style="color:#996600;">'scriptaculous'</span>, <span style="color:#996600;">'jquery'</span>, <span style="color:#996600;">'jquery-ui'</span>, <span style="color:#996600;">'jquery.delayed-observer'</span>, <span style="color:#996600;">'application'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p>
<h2>Boot Prototype Once and For All</h2>
<p>
Once you&#8217;ve eliminated all Prototype/Scriptaculous code from your project (meaning there should now be no <code class="codecolorer javascript default"><span class="javascript">$</span></code> references in your entire project, only <code class="codecolorer javascript default"><span class="javascript">$j</span></code>), you can simply remove it Prototype0+Scriptaculous from your project.
</p><p>

<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">javascript_include_tag</span> <span style="color:#996600;">'jquery'</span>, <span style="color:#996600;">'jquery-ui'</span>, <span style="color:#996600;">'jquery.delayed-observer'</span>, <span style="color:#996600;">'application'</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>

</p><p>
And just to celebrate, remove the <code class="codecolorer javascript default"><span class="javascript"><span style="color: #003366; font-weight: bold;">var</span> $j <span style="color: #339933;">=</span> jQuery.<span style="color: #660066;">noConflict</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></span></code> line from your application layout, and do a <em>Find and Replace All</em> <code class="codecolorer javascript default"><span class="javascript">$j</span></code> with <code class="codecolorer javascript default"><span class="javascript">$</span></code> for your project. You have now ditched Prototype once and for all.
</p>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/rails-prototype-to-jquery/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Printable Format for Any Webpage(and the &#8220;Meat&#8221; Algorithm)</title>
		<link>http://www.alfajango.com/blog/create-a-printable-format-for-any-webpage-with-ruby-and-nokogiri/</link>
		<comments>http://www.alfajango.com/blog/create-a-printable-format-for-any-webpage-with-ruby-and-nokogiri/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 14:21:04 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[html parsing]]></category>
		<category><![CDATA[Nokogiri]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[web scraping]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=206</guid>
		<description><![CDATA[Last week, we added functionality to one of our web apps to show just the main content of any web-page, without all the other stuff. You may think of this as creating a printable view of any web-page, with all images, videos, ads, etc. removed. Here is an example of an original webpage vs. the printable view we create.]]></description>
			<content:encoded><![CDATA[<p>
Last week, we added functionality to one of our web apps to show just the main content of any web-page, without all the other stuff. You may think of this as creating a printable view of any web-page, with all images, videos, ads, etc. removed. Here is an example of an original webpage vs. the printable view we create:
</p>
<p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/03/printable-format-before-after2.jpg"><img class="alignnone size-full wp-image-215" title="printable-format-before-after" src="http://www.alfajango.com/blog/wp-content/uploads/2010/03/printable-format-before-after2.jpg" alt="" width="550" height="261" /></a>
</p>
<p>
Feel free to skip straight to <a href="#meat-algorithm">our &#8220;Meat&#8221; Algorithm</a>, as we&#8217;ve so endearingly named it, if you&#8217;re not interested in the specifics of implementing it.
</p>
<h2>The Tools: Ruby and Nokogiri</h2>
<p>
Thanks to <a href="http://www.ruby-lang.org/en/">Ruby</a> and a Ruby gem, called <a href="http://nokogiri.org/">Nokogiri</a>, it&#8217;s far easier to create this printable view than you may think. If you haven&#8217;t heard of it before, Nokogiri is a gem that reads and parses HTML, XML, and SAX, and allows you to easily search and manipulate these documents based on CSS selectors and <a href="http://www.w3schools.com/xpath/default.asp">XPATH</a>.
</p>
<span id="more-206"></span>
<p>
<em>I should also note that Nokogiri also requires <a href="http://ruby-doc.org/core/classes/OpenURI.html">Open-URI</a>, which is included in the standard Ruby library.</em>
<h2>Reading and Parsing in 5 Lines</h2>
</p><p>
Nokogiri is really straight forward and easy to use. In fact, it&#8217;s so easy, I&#8217;m going to show you how to open any webpage and create a print-formatted version of it in 5 lines of code!
</p>
<p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'open-uri'</span><br />
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'nokogiri'</span><br />
<br />
doc = <span style="color:#6666ff; font-weight:bold;">Nokogiri::HTML</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'http://www.alfajango.com/blog/create-a-printable-format-for-any-webpage-with-nokogiri'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>config<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; config.<span style="color:#9900CC;">noent</span>.<span style="color:#9900CC;">noblanks</span>.<span style="color:#9900CC;">noerror</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
doc.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;//script&quot;</span>,<span style="color:#996600;">&quot;//img&quot;</span>,<span style="color:#996600;">&quot;//iframe&quot;</span>,<span style="color:#996600;">&quot;//object&quot;</span>,<span style="color:#996600;">&quot;//embed&quot;</span>,<span style="color:#996600;">&quot;//param&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">remove</span><br />
doc = doc.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;//p&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">collect</span><span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>p<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">parent</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">uniq</span></div></div>

</p>
<h2>Explanation: The Algorithm</h2>
<p>
Ok, so now you may be asking, what exactly is this code doing? Let&#8217;s take a look, piece-by-piece&#8230;
</p>
<h3>Setting Up the HTML with the Configuration Options</h3>
<p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">doc = <span style="color:#6666ff; font-weight:bold;">Nokogiri::HTML</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span>http:<span style="color:#006600; font-weight:bold;">//</span>www.<span style="color:#9900CC;">alfajango</span>.<span style="color:#9900CC;">com</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>config<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; config.<span style="color:#9900CC;">noent</span>.<span style="color:#9900CC;">noblanks</span>.<span style="color:#9900CC;">noerror</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>

</p>
<p>
This config block for Nokogiri is simply stripping away blank nodes, entities, and suppressing any errors generated from malformed HTML. You can <a href="http://nokogiri.org/tutorials/parsing_an_html_xml_document.html">read more about these configuration options</a> on Nokogiri&#8217;s site.
</p>
<h3>Stripping Out the Media</h3>
<p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">doc.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;//script&quot;</span>,<span style="color:#996600;">&quot;//img&quot;</span>,<span style="color:#996600;">&quot;//iframe&quot;</span>,<span style="color:#996600;">&quot;//object&quot;</span>,<span style="color:#996600;">&quot;//embed&quot;</span>,<span style="color:#996600;">&quot;//param&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">remove</span></div></div>

</p>
<p>
This line is simply removing all javascript, images, iframes, and embeded objects such as videos and flash. You can modify this to remove pretty much any elements you want from the page.
</p>

<h3>The &#8220;Meat&#8221; Algorithm: Determining What&#8217;s Important <a name="meat-algorithm">&nbsp;</a></h3>
<p>

<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">doc = doc.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;//p&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">collect</span><span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>p<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">parent</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">uniq</span></div></div>

</p>
<p>
This, believe it or not, is our algorithm for determining what is the important part of the webpage to keep. This is how we determine what the &#8220;meat&#8221; of the page is, the part that needs to be kept.
</p>
<p>
All we are doing is searching the document for <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/p.html"><span style="color: #000000; font-weight: bold;">p</span></a>&gt;</span></span></code> paragraph tags. Then we collect the parent <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></span></code> blocks (or whatever the parent elements of the <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/p.html"><span style="color: #000000; font-weight: bold;">p</span></a>&gt;</span></span></code> tags happen to be) into an array. However, if there are multiple <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/p.html"><span style="color: #000000; font-weight: bold;">p</span></a>&gt;</span></span></code> tags in one block (and let&#8217;s face it, there will be), this creates duplicate parent blocks in the array (one for each <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/p.html"><span style="color: #000000; font-weight: bold;">p</span></a>&gt;</span></span></code> tag). So, we simply call the <code class="codecolorer ruby default"><span class="ruby">.<span style="color:#9900CC;">uniq</span></span></code> method on the array to get rid of the duplicates.
</p>
<p>
Note the reason we grab the parent element of all paragraph elements (rather than just grabbing all of the paragraph elements themselves) is so that we make sure not to exclude any headings, unordered lists, ordered lists, or any other elements that may be in the body of the page, but not wrapped in paragraph tags.
</p>
<h2>95% of the Time, It Works Every Time</h2>
<p>
This is not full-proof, as there could be a webpage that throws semantics and proper markup to the wind, and decides that plain text and <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/br.html"><span style="color: #000000; font-weight: bold;">br</span></a> <span style="color: #66cc66;">/</span>&gt;</span></span></code> tags are better than <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/p.html"><span style="color: #000000; font-weight: bold;">p</span></a>&gt;</span></span></code> tags. This may also exclude other important information elsewhere in the webpage. However, in our limited experience so far, it works very well in at least 95% of scenarios.
</p>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/create-a-printable-format-for-any-webpage-with-ruby-and-nokogiri/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Performance Tuning for Phusion Passenger (an Introduction)</title>
		<link>http://www.alfajango.com/blog/performance-tuning-for-phusion-passenger-an-introduction/</link>
		<comments>http://www.alfajango.com/blog/performance-tuning-for-phusion-passenger-an-introduction/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 13:54:07 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[mod_rails]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[performance tuning]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[swap]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=142</guid>
		<description><![CDATA[Once you've launched your application and people start actually using it, you may find server experiencing excessive swapping once the traffic begins to pick up. Before getting too deep into scaling, caching, upgrading your server, etc., there are a few Passenger settings you can tune to wring out the best performance your existing stack. I'll address these settings with a few rules of thumb we've gathered from the Passenger documentation and simple trial-and-error.]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2010/03/Picture-10.png"><img class="size-medium wp-image-151 alignright" title="Picture 10" src="http://www.alfajango.com/blog/wp-content/uploads/2010/03/Picture-10-237x300.png" alt="" width="237" height="300" /></a><a href="http://www.modrails.com/">Phusion Passenger</a> (aka mod_rails) allows for easy and scalable deployment of Ruby on Rails applications on Apache or Nginx servers. Part of what makes it so easy is that it comes with suitable default settings right out of the box, so that you don&#8217;t need to concern yourself with any of the details when deploying your application to production.
</p><p>
However, once you&#8217;ve launched your application and people start actually using it, you may find server experiencing excessive swapping once the traffic begins to pick up. Before getting too deep into scaling, caching, upgrading your server, etc., there are a few Passenger settings you can tune to wring out the best performance your existing stack. I&#8217;ll address these settings with a few rules of thumb we&#8217;ve gathered from the <a href="http://www.modrails.com/documentation.html">Passenger documentation</a> and simple trial-and-error.
</p><p>
Before getting started, we highly recommend employing Munin (<a href="http://www.alfajango.com/blog/how-to-monitor-your-railspassenger-app-with-munin/">instructions for Munin with Passenger here</a>) and NewRelic Performance Monitoring for your Passenger/Rails application, so that you can fine-tune your settings for the best performance.
</p><p>
<em>Note: the following settings are specific for Apache, you will need to modify the syntax/file-names for Nginx.</em>
</p>
<h2>Per-server Settings</h2>
<p>
<span style="font-weight: normal;">These settings are set per-server, meaning if you have multiple applications running on the server, these should be set only once throughout all of your <code class="codecolorer text default"><span class="text">.conf</span></code> files. If you have only one Rails/Passenger app on the server, then you may set these in that application&#8217;s <code class="codecolorer text default"><span class="text">.conf</span></code> file. On Ubuntu, this may be found at <code class="codecolorer text default"><span class="text">/etc/apache2/sites-available/yourapp.conf</span></code>. </span>
</p>
<span id="more-142"></span>
<p>
A more appropriate place for these however would be in Apache&#8217;s <code class="codecolorer text default"><span class="text">.conf</span></code> file.
</p>
<h3>PassengerMaxPoolSize and PassengerPoolIdleTime</h3>
<p>
<code class="codecolorer text default"><span class="text">/etc/apache2/apache2.conf</span></code>:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #adadad; font-style: italic;"># PassengerMaxPoolSize</span><br />
<span style="color: #adadad; font-style: italic;"># Default: 6</span><br />
<span style="color: #adadad; font-style: italic;"># For 2gb RAM: 30</span><br />
<span style="color: #adadad; font-style: italic;"># For 256 slice with MySQL running: 2</span><br />
PassengerMaxPoolSize <span style="color: #ff0000;">2</span><br />
<br />
<span style="color: #adadad; font-style: italic;"># PassengerPoolIdleTime</span><br />
<span style="color: #adadad; font-style: italic;"># Recommended to be avg time per page * 2</span><br />
<span style="color: #adadad; font-style: italic;"># In Google Analytics... (Avg time on site / Avg page views) * 2</span><br />
<span style="color: #adadad; font-style: italic;"># Default: 300</span><br />
PassengerPoolIdleTime <span style="color: #ff0000;">150</span></div></div>

</p><p>
You can essentially copy and paste this into your apache conf file. I&#8217;ve added some notes in there to help you remember how they should be tuned.</p>
<p>
<a href="http://modrails.com/documentation/Users%20guide%20Apache.html#_passengermaxpoolsize_lt_integer_gt"><code class="codecolorer apache default"><span class="apache">PassengerMaxPoolSize</span></code></a>: This is the number of Passenger instances that can be spawned at once for your site. This basically relates directly to the amount of RAM that is available to your application. However, it is not a linear relationship. It&#8217;s more of an exponential relationship. Numbers that we and others have found to work well are:</p>
<table>
<tbody>
<tr>
<th>RAM (MB)</th>
<th>PassengerMaxPoolSize</th>
</tr>
<tr>
<td>256</td>
<td>2</td>
</tr>
<tr>
<td>512</td>
<td>6 (default)</td>
</tr>
<tr>
<td>1024 (1GB)</td>
<td>15</td>
</tr>
<tr>
<td>2048 (2GB)</td>
<td>30</td>
</tr>
</tbody>
</table>
<p>
Since this depends on available RAM, this will vary depending on what other processes are running on your server, such as MySQL, etc. If you have Munin installed with the Passenger plugins, you can monitor the Passenger Memory Stats and Passenger Status graphs to tweak this as necessary.
</p><p>
<a href="http://modrails.com/documentation/Users%20guide%20Apache.html#PassengerPoolIdleTime"><code class="codecolorer apache default"><span class="apache">PassengerPoolIdleTime</span></code></a>: This is essentially the amount of time (in seconds) that each Passenger instance continues to run after it becomes idle (i.e. someone stops clicking around the site). According to the documentation, this should be set to the average time a visitor views a page multiplied by 2. This of course prevents Passenger instances from shutting down (and thus having to re-spawn) while someone is viewing a page.
</p><p>
If your application has been in production long enough to have a few hundred viewers and you have Google Analytics installed, an easy way to get the ideal setting for your application is to take the Average Time on Site, divide by the Average Page Views per Visit, and multiply by 2.
</p><p>

<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">( Average Time on Site / Average Page Views per Visit ) x 2</div></div>

</p>
<h3>PassengerMaxInstancesPerApp (optional)</h3>
<p>
If you do have more than one Rails/Passenger application on the server, you may optionally set <code class="codecolorer text default"><span class="text">PassengerMaxInstancesPerApp</span></code>.
</p><p>
<a href="http://modrails.com/documentation/Users%20guide%20Apache.html#_passengermaxinstancesperapp_lt_integer_gt"><code class="codecolorer apache default"><span class="apache">PassengerMaxInstancesPerApp</span></code></a>: This is the maximum number of instances each application may use of the total <code class="codecolorer text default"><span class="text">PassengerMaxPoolSize</span></code>. Therefore, <code class="codecolorer text default"><span class="text">PassengerMaxInstancesPerApp</span></code> must be smaller than <code class="codecolorer text default"><span class="text">PassengerMaxPoolSize</span></code>.
</p><p>
For example, if you have 2 applications running on one 256MB server, you may want to set <code class="codecolorer text default"><span class="text">PassengerMaxInstancesPerApp</span></code> to 1, so that one app may never hog all of the rails instances at the expense of the other app. If you have 2 applications running on a 512MB server (<code class="codecolorer text default"><span class="text">PassengerMaxPoolSize</span></code> 6), then you may want to set cci]PassengerMaxInstancesPerApp[/cci] to 4 or 5 to allow each app to better handle higher load (hopefully while the other app is under less load).
</p>
<h3>RailsAutoDetect</h3>
<p>
To get a little more performance out of your server, you can also turn the <a href="http://modrails.com/documentation/Users%20guide%20Apache.html#_railsautodetect_lt_on_off_gt"><code class="codecolorer apache default"><span class="apache">RailsAutoDetect</span></code></a> setting of Passenger off. This will make it so that each request through Apache does not check to see if it is a Rails request that requires Passenger. However, this will now require that you explicitly tell Apache which requests are Rails and do require Passenger, using <a href="http://modrails.com/documentation/Users%20guide%20Apache.html#RailsBaseURI"><code class="codecolorer apache default"><span class="apache">RailsBaseURI</span></code></a>. This is easy though.
</p><p>
Again, in your <code class="codecolorer text default"><span class="text">apache2.conf</span></code> file:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #adadad; font-style: italic;"># Must be used with RailsBaseURI in Vhost</span><br />
RailsAutoDetect <span style="color: #0000ff;">off</span></div></div>

</p><p>
Now, within your the Vhost block in your site&#8217;s <code class="codecolorer text default"><span class="text">.conf</span></code> file, you will need to set the <code class="codecolorer text default"><span class="text">RailsBaseURI</span></code>:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;<span style="color: #000000; font-weight:bold;">VirtualHost</span> *:80&gt;<br />
&nbsp; ...<br />
&nbsp; RailsBaseURI /<br />
&lt;/<span style="color: #000000; font-weight:bold;">VirtualHost</span>&gt;</div></div>

</p><p>
Here is a complete example of the Passenger block in your <code class="codecolorer text default"><span class="text">apache2.conf</span></code> file:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #adadad; font-style: italic;"># PassengerMaxPoolSize</span><br />
<span style="color: #adadad; font-style: italic;"># Default: 6</span><br />
<span style="color: #adadad; font-style: italic;"># For 2gb RAM: 30</span><br />
<span style="color: #adadad; font-style: italic;"># For 256 slice with MySQL running: 2</span><br />
PassengerMaxPoolSize <span style="color: #ff0000;">2</span><br />
<br />
<span style="color: #adadad; font-style: italic;"># PassengerPoolIdleTime</span><br />
<span style="color: #adadad; font-style: italic;"># Recommended to be avg time per page * 2</span><br />
<span style="color: #adadad; font-style: italic;"># In Google Analytics... (Avg time on site / Avg page views) * 2</span><br />
<span style="color: #adadad; font-style: italic;"># Default: 300</span><br />
PassengerPoolIdleTime <span style="color: #ff0000;">144</span><br />
<br />
<span style="color: #adadad; font-style: italic;"># PassengerMaxInstancesPerApp &lt; PassengerMaxPoolSize </span><br />
PassengerMaxInstancesPerApp <span style="color: #ff0000;">1</span><br />
<br />
<span style="color: #adadad; font-style: italic;"># Must be used with RailsBaseURI in Vhost</span><br />
RailsAutoDetect <span style="color: #0000ff;">off</span></div></div>

</p></p><p>
And a simple <code class="codecolorer text default"><span class="text">sites-available/yourapp.conf</span></code> may look like this:
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;<span style="color: #000000; font-weight:bold;">VirtualHost</span> *:80&gt;<br />
&nbsp; <span style="color: #00007f;">ServerName</span> www.yourapp.com<br />
&nbsp; <span style="color: #00007f;">DocumentRoot</span> /home/deploy/yourapp/current/public<br />
&nbsp; &lt;<span style="color: #000000; font-weight:bold;">Directory</span> <span style="color: #7f007f;">&quot;/home/deploy/yourapp/current/public&quot;</span>&gt;<br />
&nbsp; &nbsp; <span style="color: #00007f;">Options</span> <span style="color: #0000ff;">FollowSymLinks</span><br />
&nbsp; &nbsp; <span style="color: #00007f;">AllowOverride</span> <span style="color: #0000ff;">None</span><br />
&nbsp; &nbsp; <span style="color: #00007f;">Order</span> <span style="color: #00007f;">allow</span>,<span style="color: #00007f;">deny</span><br />
&nbsp; &nbsp; <span style="color: #00007f;">Allow</span> from <span style="color: #0000ff;">all</span><br />
&nbsp; &lt;/<span style="color: #000000; font-weight:bold;">Directory</span>&gt;<br />
&nbsp; RailsBaseURI /<br />
&lt;/<span style="color: #000000; font-weight:bold;">VirtualHost</span>&gt;</div></div>

</p>
<h2>More Passenger Configuration Settings</h2>
<p>
These settings so far only scratch the surface of Passenger configuration. Give the <a href="http://modrails.com/documentation/Users%20guide%20Apache.html#_configuring_phusion_passenger">Passenger documentation</a> a good read-through for more information on configuring Passenger.
</p>
<h2>Further Reading: Apache Settings</h2>
<p>
At this point, if you still need to squeeze more performance out of your server (and you will eventually), you&#8217;ll want to configure Apache to utilize its resources most efficiently with Passenger. I recommend reading through <a href="http://forum.slicehost.com/comments.php?DiscussionID=1776">this thread on the Slicehost forums</a> to get a good idea just how much trial-and-error this will take. <strong>Keep a close eye on your server when you tweak these settings, you may end up making it slower several times before finding that sweet spot.</strong>
</p><p>
You may read the <a href="http://httpd.apache.org/docs/1.3/mod/core.html">documentation for each setting in the Apache docs</a> (note that these are the Apache 1.3 docs, but they still explain purpose of each setting well). For more information using these settings to reduce the RAM consumed by Apache, see <a href="http://forum.slicehost.com/comments.php?DiscussionID=3313">this other Slicehost forum</a> and <a href="http://programming-gone-awry.blogspot.com/2009/06/how-to-save-much-ram-when-running-rails.html">this blog post on saving RAM with Rails and Passenger</a>.
</p><p>
If you&#8217;re impatient and just want to get something better than default, here are some numbers that worked well for us on a recent application running on a 256MB VPS on Slicehost. These settings can be found in your <code class="codecolorer text default"><span class="text">apache2.conf</span></code> file.
</p><p>

<div class="codecolorer-container apache twitlight" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;height:300px;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #adadad; font-style: italic;"># prefork MPM</span><br />
<span style="color: #adadad; font-style: italic;"># StartServers: number of server processes to start</span><br />
<span style="color: #adadad; font-style: italic;"># MinSpareServers: minimum number of server processes which are kept spare</span><br />
<span style="color: #adadad; font-style: italic;"># MaxSpareServers: maximum number of server processes which are kept spare</span><br />
<span style="color: #adadad; font-style: italic;"># MaxClients: maximum number of server processes allowed to start</span><br />
<span style="color: #adadad; font-style: italic;"># MaxRequestsPerChild: maximum number of requests a server process serves</span><br />
&lt;<span style="color: #000000; font-weight:bold;">IfModule</span> mpm_prefork_module&gt;<br />
&nbsp; <span style="color: #00007f;">StartServers</span>          2<br />
&nbsp; <span style="color: #00007f;">MinSpareServers</span>       1<br />
&nbsp; <span style="color: #00007f;">MaxSpareServers</span>       5<br />
&nbsp; <span style="color: #00007f;">MaxClients</span>           10<br />
&nbsp; <span style="color: #00007f;">MaxRequestsPerChild</span>   100<br />
&lt;/<span style="color: #000000; font-weight:bold;">IfModule</span>&gt;<br />
<span style="color: #adadad; font-style: italic;"># worker MPM</span><br />
<span style="color: #adadad; font-style: italic;"># StartServers: initial number of server processes to start</span><br />
<span style="color: #adadad; font-style: italic;"># MaxClients: maximum number of simultaneous client connections</span><br />
<span style="color: #adadad; font-style: italic;"># MinSpareThreads: minimum number of worker threads which are kept spare</span><br />
<span style="color: #adadad; font-style: italic;"># MaxSpareThreads: maximum number of worker threads which are kept spare</span><br />
<span style="color: #adadad; font-style: italic;"># ThreadsPerChild: constant number of worker threads in each server process</span><br />
<span style="color: #adadad; font-style: italic;"># MaxRequestsPerChild: maximum number of requests a server process serves</span><br />
&lt;<span style="color: #000000; font-weight:bold;">IfModule</span> mpm_worker_module&gt;<br />
&nbsp; <span style="color: #00007f;">StartServers</span>          2<br />
&nbsp; <span style="color: #00007f;">MaxClients</span>           10<br />
&nbsp; <span style="color: #00007f;">MinSpareThreads</span>      25<br />
&nbsp; <span style="color: #00007f;">MaxSpareThreads</span>      75<br />
&nbsp; <span style="color: #00007f;">ThreadsPerChild</span>      25<br />
&nbsp; <span style="color: #00007f;">MaxRequestsPerChild</span>   100<br />
&lt;/<span style="color: #000000; font-weight:bold;">IfModule</span>&gt;</div></div>

</p>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/performance-tuning-for-phusion-passenger-an-introduction/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>
