Faster Sites Done Faster
August 12th, 2009
Google wants your site to be faster. They want it so much, they made videos! You don’t want to watch videos though, you want to make your site faster, faster. Take an hour of time and make your website 4-5x faster using these 5 high-impact techniques:
- Set HTTP Cache Headers
- Gzip Web Server Output
- Use Multiple, Cookie-less Domains for Assets
- Bundle Javascript & CSS
- Crush Image Assets
I’m going to use Rails for these examples, but you should have something comparable in any web framework. Rails got a bad rap on speed for a long time, but where the server-side code failed, the architecture won. HTTP and Rails are already in bed together, here’s how to join in.
Set HTTP Cache Headers
HTTP is your friend. Rails already handles adding timestamps to your assets URLs (that’s the ?19438273834 after the image URI. That’s why you always use image_tag), but you need to set up the HTTP headers yourself. In Apache 2 this looks like:
1 2 3 4 5 6 7 8 9 10 |
<VirtualHost *:80>
# Your config...
ExpiresActive On
<FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
Header unset ETag
FileETag None
Header unset Last-Modified
</FilesMatch>
</VirtualHost>
|
In Nginx:
1 2 3 4 5 6 |
server {
# Your config...
location ~* (css|js|png|jpe?g|gif|ico)$ {
expires max;
}
}
|
A warning to the wise- this works fairly seamlessly under Rails, but if you are on another framework be sure you have some kind of rolling argument to assets for new deploys. If not, the expires max will mean browsers will not try to pull down the new content you just deployed.
Gzip Web Server Output
Web pages, Javascript, and CSS are all text, and compress very nicely under gzip. This is a no-brainer to turn on, and it will have an immediate impact on your site. In Apache 2:
1 2 3 4 5 6 7 |
<VirtualHost *:80> # Your config... AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/x-javascript BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \\bMSIE !no-gzip !gzip-only-text/html </VirtualHost> |
In Nginx:
1 2 3 4 5 6 7 8 |
server {
# Your config...
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml text/css application/javascript;
gzip_disable msie6;
}
|
Both of these configurations bypass IE6. That’s a darn shame, if only we could make IE6 load pages faster somehow…liiike….
Use Multiple, Cookie-less Domains for Assets
This technique requires you to update your DNS entries, but it is well worth the effort. There are 2 Rails-side parts to this. One is to always use image_tag, javascript_include_tag, etc. Don’t write your own tags. Then update your asset_host configuration:
1 2 3 4 5 6 7 8 |
# In config/environments/production.rb ActionController::Base.asset_host = Proc.new { |source, request| if request and request.ssl? "https://www" # Just use one domain during SSL. This avoids mixed content errors. else "http://www#{source.hash % 4}" end + ".coolapp.com" } |
Now configure A records for each asset domain:
1 2 3 4 |
www0.coolsite.com 12.34.56.78 www1.coolsite.com 12.34.56.78 www2.coolsite.com 12.34.56.78 www3.coolsite.com 12.34.56.78 |
Lastly, configure your server. The basic configuration (again, Apache 2):
1 2 3 4 5 6 7 8 9 |
<VirtualHost *:80> ServerName www.coolsite.com ServerAlias www0.coolsite.com ServerAlias www1.coolsite.com ServerAlias www2.coolsite.com ServerAlias www3.coolsite.com # rewrite rules, etc </VirtualHost *:80> |
Of course, that leaves the whole app available on any of those domains. We can use a require condition before routing to the app so only the assets are available:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<VirtualHost *:80>
ServerName www.coolsite.com
ServerAlias www0.coolsite.com
ServerAlias www1.coolsite.com
ServerAlias www2.coolsite.com
ServerAlias www3.coolsite.com
# other config...
# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.coolsite.com$ # Only if they are asking for www
RewriteRule ^/(.*)$ balancer://coolsite_cluster%{REQUEST_URI} [P,QSA,L]
</VirtualHost *:80>
|
Set up multiple asset hosts now! If you have not done it, this is the most important technique on this page. It will make your website 3-4 times faster in most browsers. Yes, even Firefox will feel faster. Go, do it!
Bundle Javascript & CSS
Fewer downloads means less wait time for the browser. Bundle your Javascript and CSS into a single file for production. Super easy in Rails:
1 2 |
<%= javascript_include_tag 'mootools.js', 'lightbox.js', 'application.js', :cache => 'cache-application' %> <%= stylesheet_link_tag 'lightbox.css', 'application.css' :cache => 'cache-application' %> |
Crush Image Assets
Ok, this is the hardest thing on this list, and my example is the most Rails specific yet. You will need to install two applications: pngcrush and jpegtran. Both were easily installable in Gentoo, so check Ports or Apt or what-have-you. Now add this file to your project:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# lib/tasks/assets.rake namespace :assets do desc "Crush png images" task :crush_pngs do Dir['public/**/*.png'].each do |file| `pngcrush -rem alla -reduce -brute "#{file}" "#{file}.crushing"` `mv "#{file}.crushing" "#{file}"` end end desc "Crush jp(e)g images" task :crush_jpgs do ( Dir['public/**/*.jpg'] + Dir['public/**/*.jpeg'] ).each do |file| `jpegtran -copy none -optimize -perfect -outfile "#{file}.crushing" "#{file}"` `mv "#{file}.crushing" "#{file}"` end end desc "Crush images" task :crush_images do %w( assets:crush_pngs assets:crush_jpgs ).each do |task| Rake::Task[task].invoke end end end |
Now you can
1 |
rake assets:crush_images |
Review the changes, commit and push it live. These utilities are loss-less; They only strip fatty metadata not needed by browsers. Run it every time you make a large number of image changes.
Be Fast & Prove It
Before you start using these techniques, check out Firebug, Yslow, and Google Page Speed. Run the excellent IE focused WebPagetest. Gather some hard numbers before you make a change, then do some follow-up tests. Be amazed. Be fast. Get back to building your great site.
Do you have a dead simple, quick and high-impact web technique? Share it with us!

Save This On Del.icio.us
Nice links! mod rails really should do this for you, at least I think so. Regardless, another tip is to use google as your distributor for your JS [i.e. prototype] and to use a compactor for your javascript/css. Though I suppose gzip would already be helping there.