Getting camping working with fcgi on a shared host (DreamHost), part 1

Posted by Tim Connor Fri, 06 Jul 2007 16:04:00 GMT

Since I’ve been splitting up an app into an rails admin section and a separate camping front-end, I need to get camping working on the host to deploy. And that host, for this app, happens to be DreamHost, which means it’s gotta be fcgi. I’m not all the way done with that, but after a late night last night, I managed to get it running on fcgi locally. I’ll skip over the basics (for one thing, if you haven’t gotten this far yet, you are going to need to struggle through it to be familiar enough with what is happening to have a chance of finishing the process) until I have it all worked out smoothly, but I have to post a couple highlights, to spare some people with the same pain.

First off, no luck running off of edge. The only way I got it working consistently with mongrel, cgi (crucial for debugging and figuring out why things aren’t working), and fcgi, was to use the gem release (1.5.180), and patch that (keep reading). Once I had that running smoothly with the built-in server and then cgi, I got it working with fcgi. If you have the same problem I did, you’ll get an ”`camp_do’: undefined local variable or method `exc’” error. THis is because there is another problem, which is throwing an error, but there is a bug in the exception handling code. Manually fix that (change e on to exc in the exception catching, so that it is defined), and then you can move on to the next issue, since your exceptions will now actually get through to the log, or the screen, depending on how far you’ve made it, and you can use them for more debugging.

If you have my problem, you can track down the next error to the path variable not being populated right in the fastcgi.rb

    def camp_do(req)
        root, path, dir, app = "/" 
        if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
            path = req.env['SCRIPT_NAME']
        else
            root = req.env['SCRIPT_NAME']
            path = req.env['PATH_INFO']
        end
Wether or not I set ENV[‘FORCE_ROOT’] the wrong server variables are being set for camping to know the right path. This shows up as gsub on nil errors, or ”/dispatch.fcgi not found”, or some others, depending on exactly which way you are running things. This all comes back to not being able to use ScriptAlias, as in the wiki, due to only having .htaccess level access. And using RedirectRule and other mod_rewrite stuff that workins in .htaccess (I actually just stole that right from my rails .htaccess) populates things a little bit different.

My fix was to set “ENV[“FORCE_ROOT”]=1.to_s” in my dispatch.fcgi, and then change the corresponding “path =” line to match what my set-up was populating -req.env[‘REQUEST_URI’]. I tracked this down by getting things running well enough to get the default error dump to the browser, and then checking over that.

Now I need to duplicate this without using global gems (since I can’t upgrade them on the shared host), and the do more debugging on the actual host.

Getting ssl and redirect_to working without custom proxy headers

Posted by Tim Connor Tue, 03 Jul 2007 22:33:00 GMT

Since HTTP redirects are required to be fully qualified absolute paths, rails prefixes the host and protocol. And if you are using named routes _path, which returns non qualified paths, so it just checks what that protocol of the request is, and uses that. This is fine, unless you are serving https:// and you are operating from behind a proxy, in which case rails can’t know the original request was ssl so it prefixes the redirects with http:// . As a fix for that the core team added a check for the “X_FORWARDED_PROTO” header which you can add in your proxy – if you are running Apache 2.

If you are on Apache 1.3 there is no way to do this (RequestHeader is an Apache 2 only feature), so you are kinda stuck. On top of this, if you try using the spiffy ssl_requirement plug-in to enforce ssl where you want, the request will get caught in a looping redirect, since it will never know that the page is already being served up on https.

Jamis Buck wrote a work-around for serving some actions as ssl, but I wanted a simple way to have my whole site work under ssl. After digging around through the rails code, I realized you could just override the ssl? check on the request and force it to true. Of course, the request has to exist already, so I did it in a before filter.


class ApplicationController < ActionController::Base
  before_filter :set_ssl

  private
  def set_ssl;
    def request.ssl?; true; end
  end
end

You still have to set-up Apache to not serve up non-ssl, since there is no way for rails to tell the difference, but this will cause all your redirect_tos to use https://, which is the tricky part, since it’s easy to make everything else use path_only links.

I’m going to see what the boards think about honoring default_url_option[:protocol] on redirect_to(string) to obselete this, but I’ll upate if that happens.

*Or any other non fully-qualified redirecting, such as redirecting back to an original requested page, after a login, based on request_uri)