Rack map and subdomains

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

map '/' do
  run Example::Public

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

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

map '/users' do