How do I use Rack::Proxy within Rails to proxy requests to a specific path to another app

John picture John · Jun 15, 2012 · Viewed 22.4k times · Source

I found this great blog post on how to use Rack::Proxy as a separate proxy app. The article explains how he uses Rack::Proxy to proxy requests to http://localhost:3000 to an app on port 3001 and requests to http://localhost:3000/api to an app on port 3002. I want to do the same thing, but I do not want to create a separate proxy app. Instead, I want my main Rails app to proxy requests to /blog to a different app.

Blog Post: http://livsey.org/blog/2012/02/23/using-rack-proxy-to-serve-multiple-rails-apps-from-the-same-domain-and-port/

Answer

steve picture steve · Nov 24, 2012

FWIW, I also just tackled this problem. Some may find the full code helpful, as I needed more than you posted:

# lib/proxy_to_other.rb
class ProxyToOther < Rack::Proxy
  def initialize(app)
    @app = app
  end

  def call(env)
    original_host = env["HTTP_HOST"]
    rewrite_env(env)
    if env["HTTP_HOST"] != original_host
      perform_request(env)
    else
      # just regular
      @app.call(env)
    end
  end

  def rewrite_env(env)
    request = Rack::Request.new(env)
    if request.path =~ %r{^/prefix|^/other_prefix}
      # do nothing
    else
      env["HTTP_HOST"] = "localhost:3000"
    end
    env
  end
end

Also:

# config/application.rb
# ...snip ...
module MyApplication
  class Application < Rails::Application
    # Custom Rack middlewares
    config.middleware.use "ProxyToOther" if ["development", "test"].include? Rails.env
#...snip....

This assumes your app you want to proxy some requests to is running on port 3001. I daresay the app you're hitting can be run on any port. This also assumes you only want to do the proxying in development and test environments, because you'll have a 'real' solution in production & staging (eg, nginx or a loadbalancer doing the proper thing).