Nginx Reverse Proxy Config for Rails 4 ActionController::Live Streaming

I have been working with streaming data sources on my current project and I needed to implement a way to stream the contents of Apache Kafka topics over HTTP with 1:N connection fanout. As a quick test, I implemented an ActionController::Live streaming controller in Rails 4, and I ran into some trouble with my Nginx reverse-proxy config for Rails. Specifically, the streaming response from the upstream Rails application would prematurely terminate, closing the downstream Nginx connection to the client and terminating the streaming response. I had to do a lot of searching and trial and error testing to find a working Nginx reverse-proxy config for Rails live streaming, so I thought I would capture it here to save others the trouble.

First, some version info:

  • Nginx: 1.5.8 (testing on both Mac OS X and CentOS)
  • Rails: 4.0.2
  • ruby 2.0.0-p353

As a simple test, I implemented the following action using ActionController::Live streaming. Note the use of the X-Accel-Buffering HTTP header to inform Nginx to turn off proxy buffering for requests to this action. Alternatively, you can uncomment proxy_buffering in the nginx location config to eliminate buffering for all Rails requests, but it is probably safer to selectively disable response buffering via the header.


class OutboundsController < ApplicationController
  include ActionController::Live

  def consumer
    response.headers['Content-Type'] = 'application/json'
    response.headers['X-Accel-Buffering'] = 'no'

    10.times { |i|
      hash = { id: "#{i}", message: "this is a test, message id #{i}" }
      response.stream.write "#{JSON.generate(hash)}\n"
      sleep 1
    }

    response.stream.close
  end

end

The Nginx reverse-proxy config that finally worked for me is as follows. I’m only listing the bits I added to my otherwise “standard” nginx setup.


http {

...

  map $http_upgrade $connection_upgrade {
    default Upgrade;
    '' close;
  }

...

}

upstream rails {
  server localhost:3000;
}

server {

...

  location / {
    proxy_pass http://rails;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #proxy_buffering off; # using X-Accel-Buffering: off in ActionController:Live
    break;
  }

...

}

With this config, I get the expected output — {“id”:”0″,”message”:”this is a test, message id 0″}, one per second, with incrementing IDs — streamed all the way through to my client.

One other note: if you are using curl as your client, be sure to set --no-buffer to avoid any client-induced delays in streaming data arrival.

That’s it. Hope this helps.

One thought on “Nginx Reverse Proxy Config for Rails 4 ActionController::Live Streaming

  1. Hi blogger, i must say you have very interesting content
    here. Your page can go viral. You need initial traffic only.
    How to get it? Search for; Mertiso’s tips go viral

Leave a Reply

Your email address will not be published. Required fields are marked *