skip to Main Content

I have an app in Sinatra that accepts requests at the root and with a name using:

get '/'
  'Root page'
end

get '/:name'
  #Some code here
end

When hosting the application behind a reverse-proxy using a sub-directory (i.e. http://some.thing/news points to http://localhost:4567/ ), I want to have /news to go to the get '/' route and /news/old to go to the get '/:name' route.

What configuration does Sinatra need for it to know that it’s hosted within a virtual directory and not at the root of the domain? Is this even possible?

The environment within which the application is deployed uses Apache as a reverse-proxy. To re-create the scenario for a quick test, I set up nginx on my computer with:

location /news {
  proxy_pass http://localhost:4567;
}

Going to /news causes it to go to the /:name route instead of the / route.

2

Answers


  1. Instead of trying to approach the problem from the framework, we can solve the problem from the reverse-proxy.

    Nginx has the ability to rewrite the URL. For example:

    location /news { 
      rewrite /news(.*) /$1 break;
      proxy_pass http://localhost:4567;
    }
    

    Apache does not need any configuration apart from defining the ProxyPass directive. Here’s me entire httpd.conf file:

    ServerRoot "/opt/homebrew/opt/httpd"
    Listen 127.0.0.1:1082 
    ServerName Nitins-MacBook
    
    LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so
    LoadModule log_config_module lib/httpd/modules/mod_log_config.so
    LoadModule unixd_module lib/httpd/modules/mod_unixd.so 
    LoadModule authz_core_module lib/httpd/modules/mod_authz_core.so
    
    LoadModule mime_module lib/httpd/modules/mod_mime.so 
    AddType text/html .html
    
    DocumentRoot "/Users/nitin.katkam/Documents/practice/frabjous/"
    CustomLog "/Users/nitin.katkam/Documents/practice/omniauthgh/httpd_log" common
    ErrorLog "/Users/nitin.katkam/Documents/practice/omniauthgh/httpd_err_log"
    
    LoadModule proxy_module lib/httpd/modules/mod_proxy.so 
    LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so 
    
    <Location "/snow"> 
      ProxyPass "http://localhost:3000"
    </Location>
    

    Absolute URLs within the HTML are not automatically re-written and may need more configuration settings.

    Login or Signup to reply.
  2. Using the reverse proxy is a good way, as the other answer shows, but sometimes you may not have access to that, or you simply want to stay in Ruby, then you can also do this using Rack’s config.ru via the map method, which you can see in the Sinatra docs:

    # config.ru (run with rackup)
    require 'sinatra/base'
    
    controller = Sinatra.new do
      enable :logging
      helpers MyHelpers
    end
    
    map('/a') do
      run Sinatra.new(controller) { get('/') { 'a' } }
    end
    
    map('/b') do
      run Sinatra.new(controller) { get('/') { 'b' } }
    end
    

    and as this helpful Sitepoint tutorial shows:

    require 'sinatra/base'
    
    Dir.glob('./{models,helpers,controllers}/*.rb').each { |file| require file }
    
    SongController.configure :development do
      DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/development.db")
    end
    
    SongController.configure :production do
      DataMapper.setup(:default, ENV['DATABASE_URL'])
    end
    
    map('/songs') { run SongController }
    map('/') { run WebsiteController }
    

    So in your case, where you want:

    • /news => get '/' and
    • /news/old => get '/:name'
    # news.rb
    
    class News < Sinatra::Base
      get '/' do
        'Root page'
      end
    
      get '/:name' do
        #Some code here
      end
    end
    
    # config.ru
    
    require_relative "news.rb"
    
    map('/news') do
      run News
    end
    

    Then run rackup config.ru -p 4567. You could even, if your code is short enough, approach the Sinatra docs’ example even more, e.g.

    # config.ru
    map("/news") do
      Sinatra.new do
        get '/' do
          'Root page'
        end
    
        get '/:name' do
          #Some code here
        end
      end
    end
    

    That way you can start to organise your routes and reuse code how you like.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search