You think 1 site equals 1 Apache Virtual Host? Think again, and read on to figure out why not.
For every Rails application that I deploy into production mode, I usually creates 3 Virtual Host entries in Apache. To illustrate, here is the setup for our dog-site www.gipote.dk:
Note: This setup is using Passenger (aka. mod_rails). If you are not already using it for your Rails production environment, you really should do so. It’s the best thing happened since Rails itself.
ServerName www.gipote.dk DocumentRoot /var/www/rails/gipote_production/public RailsEnv production ServerName asset0.gipote.dk ServerAlias asset1.gipote.dk ServerAlias asset2.gipote.dk ServerAlias asset3.gipote.dk DocumentRoot /var/www/rails/gipote_production/public PassengerEnabled off ServerName gi-pote.dk ServerAlias *.gi-pote.dk ServerAlias *.gipote.dk RewriteEngine on RewriteRule ^(.*) http://www.gipote.dk$1 [R=301] PassengerEnabled off
The *=”" inside my virtual host declations is the WordPress SyntaxHighlighter playing tricks on me. It should just be an *
Some explanation is required…
First of all, I want one and only one entry into our site. This originally came from making it easier to setup Google Analytics (you need to tweak the tracking code to support multiple domains). But it seems that it also improves our SEO rankings – so more power to us.
So the first virtual host only accepts www.gipote.dk. The last virtual host accepts all other variations on gipote.dk (except a few – I’ll come to that) as well as an entirely different domain gi-pote.dk. The last virtual host redirects all these requests to www.gipote.dk.
The last virtual host relly must be placed at the bottom, since it contains wildcards. These wildcards – *.gipote.dk – will catch all hostnames not specified in any virtual host above it. Position is vital.
Now to the second virtual host. It requires a bit more explaining…
Internet Explorer and Firefox has a limit when fetching a webpage concerning concurrent connections to the same host. They will only have 2 open connections to a single host at a time. So if you have a page with many external files – or assets (css, js, images), you may find, that it is slow to load, even if you have a powerful server. The bottleneck is at the client this time.
Rails have a fix for this: Every asset specified in the ERB by the asset helpers image_tag(), stylesheet_link_tag(), etc. Can automatically prepend the URL with an asset host. You need to define the asset host in your config/environments/production.rb file:
config.action_controller.asset_host = "http://asset%d.gipote.dk"
The %d is important. This will make Rails’ asset helpers prepend either of
http://asset0.gipote.dk http://asset1.gipote.dk http://asset2.gipote.dk http://asset3.gipote.dk
to any asset url. It will use exactly these 4 variants, and they will be distributed (almost) evenly out on your assets.
So image_tag(‘logo.png’) will become http://asset2.gipote.dk/images/logo.png (or 0, 1, 3).
The cool thing about this is, that the aforementioned browsers will open 2 connections for each host. So instead of fetching 2 assets concurrently, your browser will now fetch 8 at the same time.
So we need our Apache to deal with this. We cannot rely on the last virtual host to do this, because it will simply redirect to www.gipote.dk. And we don’t want to add these 4 hostnames as alias’ to the top virtual host, because we don’t want our users to be able to access our Rails application by any other hostname than www.gipote.dk.
So I create the second virtual host. Put in all 4 hostnames, point it to my Rails public folder. Oh – and for good performance measure, I disable Passenger (PassengerEnabled off). Otherwise the users would still be able to use the hostnames to access our application.