multiple rails apps on nginx and unicorn

2019-01-16 14:00发布

问题:

I successfully setup a rails site using the Screencast 335 deploy to a VPS tutorial. Now I want to add another rails app on a new domain but I am confused about the steps required.

In the above setup, there are no changes to sites-available or /etc/nginx/nginx.conf. The only configuration is in unicorn.rb, unicorn_init.sh and nginx.conf in my apps config directory. The nginx.conf file looks like this:-

upstream unicorn {
  server unix:/tmp/unicorn.my_app.sock fail_timeout=0;
}
server {
  listen 80 default deferred;
  # server_name my_app.com.au www.my_app.com.au;
  root /var/www/my_app/current/public;
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }
  try_files $uri/index.html $uri @unicorn;
  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;
  }
  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

In my Capistrano recipe I have this line

sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"

Is adding a second domain merely a matter of removing default deferred after listen and un-commenting the server_name section then repeating this config file with a different upstream socket name and server name for the second app? Will that work or do I need to transfer this file to sites-available and create a symbolic link to sites-enabled?

回答1:

It is really easy to host different apps on one host with Nginx and Unicorn.

The separation you can get by defining different names of the socket files of each application. Of course you should point the right current/public directories in the server section of nginx.conf.

The last touch is in the unicorn_init.sh file: on the top of it you should change APP_ROOT with the full path to current/public directory of your application.

If your setup is similar to the RailsCast's one, all the other things are done by capistrano .



回答2:

In unicorn.rb:

application 1:

root = "/var/www/application_1/current"
working_directory root
pid "#{root}/tmp/pids/unicorn-app1.pid"
listen "/tmp/unicorn.app1.sock"

application 2:

root = "/var/www/application_2/current"
working_directory root
pid "#{root}/tmp/pids/unicorn-app2.pid"
listen "/tmp/unicorn.app2.sock"

In nginx.conf:

application 1:

upstream app1_server {
  server unix:/tmp/unicorn.app1.sock fail_timeout=0;
}

server {
  listen 80;
  server_name my_app_1.com www.my_app_1.com;
  root /var/www/app1/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @app1_server;
  location @app1_server {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_pass http://app1_server;
 }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

application 2:

upstream app2_server {
  # point to app2 sock
  server unix:/tmp/unicorn.app2.sock fail_timeout=0;
}

server {
  listen 80;
  server_name my_app_2.com www.my_app_2.com;
  root /var/www/app2/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @app2_server;
  location @app2_server {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_pass http://app2_server;
 }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}


回答3:

I answered this on a question I made myself here:

Multiple Rails 4 app using nginx + unicorn

But here's a answer:

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.