Nginx and Unicorn on separate machines

load balancingnginxruby-on-railsunicorn

I've got a pretty standard Rails application running with Unicorn and Nginx all on one box. I'd like to split off the application itself and have Nginx on one machine and Unicorn (with the Rails app) on another machine. The idea here being that I'd like to add another app server with Unicorn later in the future, mostly for some light load balancing.

I may be tackling this from the wrong angle. Is this normal/possible? If so, can someone point me to example configs or documentation?

If it's not the way to go, what's the proper route to achieve the end goal? I've looked into HAProxy, but after reading through some Nginx/Unicorn documentation, I get the idea that this can be achieved without any additional software.

Best Answer

This is normal. You don't need HAProxy, though HAProxy may provide you with "fairer" load balancing between the app servers than the nginx load balancing.

So, on your app servers, set Unicorn to listen a network interface. This should preferably be a private IP address. For this example, let's say your app servers are 192.168.1.100, 192.168.1.101 and 192.168.1.102. Configure unicorn to listen to port 8000 on all the app servers.

On the nginx side, you'll have an "upstream" block like:

upstream unicorn {
  server 192.168.1.100:8000;
  server 192.168.1.101:8000;
  server 192.168.1.102:8000;
}

Then you will have your virtual server definition with a block like:

location / {

    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X_FORWARDED_PROTO $scheme;
    proxy_set_header  Host $host;

    proxy_connect_timeout 3;
    proxy_read_timeout 60;
    proxy_send_timeout 60;

    proxy_redirect off;
    proxy_max_temp_file_size 0;

    if (!-f $request_filename) {
      proxy_pass http://unicorn;
    }
}

You may need other proxy statements to get things to work like you want, but that should essentially do it. The proxy_pass statement will use the block defined in the upstream block, and will distribute jobs to the listed app servers. Check nginx documentation on other options that might be appropriate.