Search code examples
ruby-on-railsnginxunicorn

Multiple Rails 4 app using nginx + unicorn


I'm looking for set up a nginx server with unicorn. I the first app is set but it's on the root "/". what i really want is type localhost/app1 and it would run, while if a just enter to the root, html or php pages are going to be open.

Any clue?

Here's the current nginx.config:

worker_processes 4;

user nobody nogroup; # for systems with a "nogroup"

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # "on" if nginx worker_processes > 1
}

http {
  include mime.types;


  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;

  tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
  tcp_nodelay off; # on may be better for some Comet/long-poll stuff

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/html text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream sip {
    server unix:/home/analista/www/sip/tmp/sockets/sip.unicorn.sock fail_timeout=0;
  }

  server {

    listen 80 default deferred; # for Linux


    client_max_body_size 4G;
    server_name sip_server;

    keepalive_timeout 5;

    # path for static files
    root /home/analista/www/sip/public;

    try_files $uri/index.html $uri.html $uri @app;

    location @app {

      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
      proxy_set_header Host $http_host;
      proxy_redirect off;   
      # proxy_buffering off;

      proxy_pass http://sip;
    }

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      if (!-f $request_filename) {
        proxy_pass http://sip;
        break;
      }
    }

    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /home/analista/www/sip/public;
    }
  }
}

Solution

  • I've got it! Turns out it was really simple and I wrote a post about it on my blog. http://jrochelly.com/post/2013/08/nginx-unicorn-multiple-rails-apps/

    Here's the content:

    I'm using Ruby 2.0 and Rails 4.0. I suppose you already have nginx and unicorn installed. So, let's get started!

    In you nginx.conf file we are going to make nginx point to a unicorn socket:

    upstream unicorn_socket_for_myapp {
      server unix:/home/coffeencoke/apps/myapp/current/tmp/sockets/unicorn.sock fail_timeout=0;
    }
    

    Then, with your server listening to port 80, add a location block that points to the subdirectory your rails app is (this code, must be inside server block):

    location /myapp/ {
        try_files $uri @unicorn_proxy;
      }
    
      location @unicorn_proxy {
        proxy_pass http://unix:/home/coffeencoke/apps/myapp/current/tmp/sockets/unicorn.sock;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
      }
    

    Now you can just Unicorn as a Deamon:

    sudo unicorn_rails -c config/unicorn.rb -D
    

    The last thing to do, and the one I dug the most is to add a scope for your rails routes file, like this:

    MyApp::Application.routes.draw do
      scope '/myapp' do
        root :to => 'welcome#home'
    
        # other routes are always inside this block
        # ...
      end
    end
    

    This way, your app will map a link /myapp/welcome, intead of just /welcome

    But there's a even better way

    Well, the above will work on production server, but what about development? Are you going to develop normally then on deployment you change your rails config? For every single app? That's not needed.

    So, you need to create a new module that we are going to put at lib/route_scoper.rb:

    require 'rails/application'
    
    module RouteScoper
      def self.root
        Rails.application.config.root_directory
      rescue NameError
        '/'
      end
    end
    

    After that, in your routes.rb do this:

    require_relative '../lib/route_scoper'
    
    MyApp::Application.routes.draw do
      scope RouteScoper.root do
        root :to => 'welcome#home'
    
        # other routes are always inside this block
        # ...
      end
    end
    

    What we are doing is to see if the root directory is specified, if so use it, otherwise, got to "/". Now we just need to point the root directory on config/enviroments/production.rb:

    MyApp::Application.configure do
      # Contains configurations for the production environment
      # ...
    
      # Serve the application at /myapp
      config.root_directory = '/myapp'
    end
    

    In config/enviroments/development.rb I do not specify the config.root_directory. This way it uses the normal url root.