haproxy rails security server

(A german version is available at the kaupert media website)

We use HAProxy as the load balancing frontend to forward incoming requests to Apache+Passenger instances for a client’s web app.

Problems arose on the HAProxy machine itself which was also forwarding requests to a locally running Apache as part of the available application backends: despite using the forward_for option for the configured backend, Rails considered all incoming requests local as they were indeed coming from the local machine. The result was exposed exceptions, even on something as trivial as a RoutingError which should trigger a normal 404 page.

Wesley Moxam described this problem in a blog post, but our setup is slightly different: HAProxy sends requests directly to Passenger/mod_rails within Apache vhosts without Apache-side (double)proxying involved. Removing the option forward_for as described in said post was no viable way to go for us as it confused the non-local nodes in the setup.

Heaving the formally locally running instance onto the external interface and treating it just as any other node rid us of the first problem and adding your HAProxy to the list of TRUSTED_PROXIES fixes the second. Add the following line as an initializer to your Rails 2.3.x app. The HAProxy backend uses option httpclose and option forward_for.

# config/initializers/trusted_proxies.rb
# If your HAProxy is running at IPv4 address a.b.c.d, set:
ActionController::Request.const_set("TRUSTED_PROXIES", /^a\.b\.c\.d$|^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i)

Granted, I don’t feel overly comfortable with coding that bit of network architecture into my Rails application. Moving servers and switching IPs is pain enough as it stands and thus I don’t like adding another dependency. It works, though, and here’s to hoping that our load balancer does not have to be exchanged anytime soon.

comments powered by Disqus