All posts

Fix Load Balancer Error in Ruby

Resolve load balancer issues for Ruby web apps using Sinatra, Rack, or Puma, covering proxy headers and connection keep-alive settings.

Ruby Web Apps Behind Load Balancers

Whether you're using Sinatra, Hanami, or raw Rack, Ruby web apps behind a load balancer need proxy header handling and proper server configuration.

Rack Proxy Headers

Use the rack-proxy-headers middleware or handle it manually:

# config.ru
require 'rack'

class ProxyFix
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['HTTP_X_FORWARDED_PROTO'] == 'https'
      env['rack.url_scheme'] = 'https'
      env['HTTPS'] = 'on'
    end
    if env['HTTP_X_FORWARDED_FOR']
      env['REMOTE_ADDR'] = env['HTTP_X_FORWARDED_FOR'].split(',').first.strip
    end
    @app.call(env)
  end
end

use ProxyFix
run MyApp

Puma Configuration

# config/puma.rb
bind 'tcp://0.0.0.0:3000'
workers ENV.fetch('WEB_CONCURRENCY', 2).to_i
threads_count = ENV.fetch('RAILS_MAX_THREADS', 5).to_i
threads threads_count, threads_count

# Important for load balancers
first_data_timeout 30
persistent_timeout 20

The persistent_timeout should be shorter than your load balancer's idle timeout to prevent connection reuse errors.

Sinatra Health Check

get '/healthz' do
  status 200
  'ok'
end

Keep-Alive Mismatches

If you see intermittent 502 errors, it's usually because Puma closes keep-alive connections before the load balancer expects. Align the timeouts:

ALB idle timeout: 60s
Puma persistent_timeout: 75s  ← Keep higher than ALB

Bugsly's Ruby integration captures exceptions from any Rack-based framework, including the real client IP after proxy header processing.

Try Bugsly Free

Track up to 100 issues per month on the free plan, with unlimited events and no credit card required.

Get Started Free