Thank god for Ruby and DSLs. Gone are the days of developers resigned to using apache and having to mess with it’s arcane configuration syntax. The plethora of webservers used these days combined with simplicity and power of Rack middleware makes for a much simpler life for us rubyists.

Thanks to a variety of Rack middleware,  Bindle is faster, more efficient, and has better access for the Googlebot. This post will give you some tips to do the same.

We have a pretty standard setup:

  • Rails 3.1
  • Ruby 1.9
  • Heroku Cedar


Got some assets on your site that are expensive to generate? Thinking about the CPU cost of repeated access? Well worry no more, a reverse proxy cache [1] will make that problem disappear. For some examples, consider dragonfly, reverse_proxy and split_assets below. As a bonus: googlebot stays happy when things are fast.

We use memcached to actually keep the cache around, which is easily accomplished on Heroku. Though also Heroku adds rack/cache for you, others may want to do something like:

config.middleware.use Rack::Cache


GZipped assets are good. It’s really this simple to get it going on your server, simply add:

config.middleware.insert_before Rack::Cache, Rack::Deflater

You want the deflater to be outside of the cache, I fear strange things may happen otherwise.


Task 1: Rails defaults to generating URLs like However, it’s possible the Googlebot will find a link like Since Google doesn’t like duplicate content, we need to 301 redirect that trailing slash away.

Task 2: We also employ a URL shortener which redirects requests from and to to simplify the user experience and retain the google juice in a single domain.

config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
  # anything ending in / to the same without the '/'
  r301 %r{(.+)/$}, '$1'
  # -> (will then go to the shortener)
  r301 %r{.*}, '$&', :if => { |rack_env|
    ['', ''].include?(rack_env['SERVER_NAME'])


PageRank doesn’t transfer between subdomains particularly well. So instead of hosting your blog at it’s better to use a subdirectory format like However, you might not want to use Rails for your blog; perhaps you prefer WordPress, or you’d like to use an external site like Tumblr. How do you redirect your blog from a subdomain to a subdirectory behind Heroku? Enter rack/reverse_proxy. Even though we don’t have access to the webserver, we don’t have to care thanks to rack.

config.middleware.insert_after(Rack::Cache, Rack::ReverseProxy) do
  reverse_proxy %r{^/blog(.*)$}, '$1', :preserve_host => true


Dragonfly adopts the philosophy of generating thumbnails on the fly. Bindle generates somewhere along the lines of ten different thumbnails for each image that is uploaded. Instead of worrying about image storage in the cloud, we generate the necessary images on the fly and store them in memory with memcached.

For example this is what we use to integrate Dragonfly into rack:

config.middleware.insert_after Rack::Cache, Dragonfly::Middleware, :images


IE throws up some interesting problems. The split asset endpoint solved a particularly thorny one for me:

config.middleware.insert_after Rack::Cache, 'SplitAssetEndpoint', '/split_assets'

Any other interesting middleware you’re using in your projects?

  1. I’m still trying to work out if us Australians, who pronounce it ‘kay-shh’ rather than ‘cash’ are wrong. I feel we probably are—it’s a French word after all. []
Tom Coleman

Co-creator of, searching for simplicity, quality and elegance in technology, products and code.

See all Tom Coleman's posts

2 Responses to “Rack Middleware for SEO, fun and profit”

  1. Xavier Riley says:

    I’ve just published my first gem – RackSeo which adds sensible meta information and keywords based on the text content in the page. Might make a good addition to your list?

  2. [...] to host the blog on a subdirectory instead of a subdomain. This post was an immense help to us Rack Middleware for SEO Fun and Profit [...]

Leave a Reply

  • Search: