views:

278

answers:

4

I have an Rails application server that is listening on port 9000, and is being called through haproxy. All my redirects from that server are being redirected back through port 9000, when they should be sent back on port 80.

I am using a combination of haproxy + nginx + passenger. Is there a way to make sure all redirects are being sent through port 80, regardless of what port the actual server is listening on?

I don't care if its a haproxy, nginx, Passenger, or Rails change. I just need to make sure most requests unless specified otherwise, are sent back to port 80.

Thanks!

+1  A: 

Rewriting the redirect should probably be the web server's responsibility, but you can hack the request object to always return port 80 in a before_filter:

class ApplicationController < ActionController::Base
    before_filter :use_port_80 if RAILS_ENV == production
    def use_port_80
        class << request
            def port; 80; end
        end
    end
end
elektronaut
This may work, but it feels very much like a driving a small nail in with a giant sledge hammer. I also wonder if there might be other side effects to overriding the port method like you have shown.
Scott S.
A: 

If this are links that are linked to the same server as site the site they are on. You can use relative links instead of absolute ones. If you're using helper methods to create the links you can use the _path suffix instead of _url.

If your routes.rb looks something like this:

ActionController::Routing::Routes.draw do |map|
  map.resources :users
end

or in rails 3:

YourAppName::Application.routes.draw do
  resources :users
end

you can use the following helper methods to create relative links:

users_path     #=> /users
user_path      #=> /users/:id
edit_user_path #=> /users/:id/edit
new_user_path  #=> /users/new

# instead of

users_url      #=> http(s)://example.com:9000/users
user_url       #=> http(s)://example.com:9000/users/:id
edit_user_url  #=> http(s)://example.com:9000/users/:id/edit
new_user_url   #=> http(s)://example.com:9000/users/new

As you can see, these links are independent of the port or host you're running on.

jigfox
I do need the `_url` because I am generating a URL to have OpenID redirect back to. Once the redirect is finished, the server is thinking its on port :9000. I also don't have much control over the generated URL.
Garrett
+3  A: 

Like elektronaut indicated, this is probably something that should be handled in your proxy's configuration. That said, ActiveSupport::UrlFor#url_for has some information that might be useful. Take a look at http://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/url_for.rb

What I think it boils down to is passing two arguments into your url_for and/or link_to calls. First is the :port => 123 argument, the second is :only_path => false so that it generates the full link including domain, port, etc.

So when generating a link, you might do:

link_to 'test', root_url(:port => 80, :only_path => false)

and when creating a custom url you might do:

url_for :controller => 'test', :action => 'inde'x, :port => 80, :only_path => false

For a redirect:

redirect_to root_url(:port => 80, :only_path => false)

I hope this helps, and if it doesn't, can you be more specific about how you generating your URLs, what rails is generating for you, and what you would like it to generate.

Update: I wasn't aware of this, but it seems you can set defaults for the URL's rails generates with url_for, which is used by everything else that generates links and/or URLs. There is a good write up about it here: http://lucastej.blogspot.com/2008/01/ruby-on-rails-how-to-set-urlfor.html

Or to sum it up for you:

Add this to your application_controler.rb

def default_url_options(options)
   { :only_path => false, :port => 80 }
end

and this:

helper_method :url_for

The first block sets defaults in the controllers, the second causes the url_for helper to use the one found in the controllers, so the defaults apply to that as well.

Scott S.
I just found out about setting defaults for url_for. I've updated this post with all of the info. It's a much cleaner solution.
Scott S.
+1  A: 

I propose it should be fixed in haproxy by adding this code to the config.

rsprep (.*):9000(.*) \1\2
thomasfedb
Of course you may need multpile entries if you are using many nginx/rails ports.
thomasfedb
Where exactly does this go? Within the backend blocks or the frontend blocks?
Garrett
From what i can tell from the haproxy manual (not much) this should go in backend. But if that has issue then try frontend.
thomasfedb