Rack map and subdomains

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.
  

Possibly similar articles