Rack map and subdomains

Tagged
rack ruby nginx

The situation

You are using subdomains for locales such as en.example.com and th.example.com. Your app is Rack based and is behind Nginx with a ‘wildcard’ server_name directive such as:

server {
  server_name .example.com;
  ...
}

You are also using Rack’s map abilities to have two different applications mounted on different paths on your domain. This could be done like this in your config.ru file:

map '/users' do
  run Example::Admin
end

map '/' do
  run Example::Public
end

The problem

If the URL http://th.example.com is hit, Nginx will set ‘HTTP_HOST’ as ‘th.example.com’ but ‘SERVER_NAME’ will be ‘example.com’. What his means is that tests within Rack fail and result in neither of the above ‘maps’ matching so a 404 is returned.

A solution

In Rack apps you are able to modify the environment. This means that one way to fix this is to simply set the environment’s’ SERVER_NAME’ to equal ‘HTTP_HOST’ by including something like this in your config.ru file, before your map calls:

module Rack
  class Blah
    def initialize app
      @app = app
    end

    def call env
      env['SERVER_NAME'] = env['HTTP_HOST']
      @app.call env
    end
  end
end
use Rack::Blah

map '/users' do
...etc.