Rack map and subdomains

Updated 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.