Running Multiple Rails Apps on Nginx

evilelvi edited this page Aug 12, 2012 · 6 revisions

This guide assumes you have completed the Nginx Server Configuration guide. If you have not completed the Git Deployment with Capistrano guide, all instances of

/var/www/testapp/current/public

should be replaced with

/var/www/testapp/public 

In order to have multiple Rails apps running on the same server, we have to reconfigure both Nginx and Unicorn.

Configuring Your Hosts File

We need to hit our server from two different domains to confirm nginx is properly routing our requests to the correct app corresponding to the domain. Unless you already have two domain names attached to your server with propogated DNS, we'll need to simulate requests using the hosts file.

First, get the public IP address of your server. You can generally get this through an admin panel. In the event you can't find it in your admin panel, execute the following on your server:

$ curl http://httpbin.org/ip

Now open up your hosts file. This is generally located at /etc/hosts and usually requires root permissions to edit.

$ sudo vim /etc/hosts

Our domain names will simply be railsapp1.com and railsapp2.com. Suppose your IP address is 99.99.99.99. Append the following to the hosts file.

    # Rails test servers
99.99.99.99 railsapp1.com
99.99.99.99 www.railsapp1.com
99.99.99.99 railsapp2.com
99.99.99.99 www.railsapp2.com

If you visit http://railsapp1.com in your browser, you should see the rails landing page.

Preparing the apps

If you completed the Nginx configuration guide, then you have a testapp directory in /var/www/testapp. For the sake of naming consistency with our domains, we will rename this directory, create a copy of it, and make some slight modifications to the copy to differentiate.

$ cd /var/www
$ mv testapp railsapp1.com
$ cp -R railsapp1.com railsapp2.com
$ cd /var/www/railsapp2.com/app/views/pages
$ vim show.html.erb 

Change the contents of the show.html.erb file to

<h2>This is the second app!</h2>

We aren't through configuring these apps, but we'll come back to that later.

Reconfiguring Nginx

Replace the contents of the /etc/nginx/nginx.conf file with the contents of this gist

Now cd into the sites-enabled nginx directory.

$ cd /etc/nginx/sites-enabled
$ ls
default

Remove the default symlink.

$ sudo rm /etc/nginx/sites-enabled/default

Now cd into the sites-available directory.

$ cd /etc/nginx/sites-available

** A quick note on sites-enabled vs sites-available **
The sites-available directory is where you store configuration files for sites. The sites-enabled directory is where you create symbolic links those configuration files when they are ready to be made active.

We still have some Nginx configurations left to do, but these configurations must line up with Unicorn configurations, so we handle that in the next section.

Hooking Up Nginx + Unicorn

With the initial Nginx + Unicorn configurations, we didn't have to worry about conflicting sockets, ports, or anything of that nature. Now that we are running multiple apps, we need to take these properties into account whenever we are configuring our Nginx virtual hosts and our unicorn.rb file.

Take note that the following properties (which we will cover in detail) must be unique between apps/virtual hosts:

  • sockets
  • ports
  • upstream names

Nginx

Head over to your sites-available folder.

$ cd /etc/nginx/sites-available

Create a file named railsapp1.com. Paste in the contents of this gist.

$ sudo vim railsapp1.com

Now copy this file to a file named railsapp2.com

$ sudo cp railsapp1.com railsapp2.com

Now edit railsapp2.com, and replace all instances of railsapp1 with railsapp2.

$ sudo vim railsapp2.com

I've documented the important parts of the gist, so take a few minutes to look through it and understand the commented portions.

As described earlier, site configurations in the sites-available will not be active unless you make a symbolic link to the file in the sites-enabled directory. You should have the nginx_enable() and nginx_disable functions in your ~/.bashrc from following the other guides. If you don't have those functions, grab them from this gist and append them to your ~/.bashrc

We will now enable these two sites

$ nginx_enable railsapp1.com
$ nginx_enable railsapp2.com

With the exception of performance modifications you can make on your own, you're finished configuring Nginx!

Unicorn

Now we must configure the unicorn.rb file of each app to match their respective nginx configurations.

Let's move to railsapp1

$ cd /var/www/railsapp1.com/current

Now we open up the unicorn.rb file

    $ vim config/unicorn.rb

If your APP_PATH still reads /var/www/testapp/current, change that to the proper directory. If you've been following this guide word for word, that would be /var/www/railsapp1.com/current

At this point, there are only two more configurations to make. Locate the lines around the middle of the file that begin with "listen" See here

The first listen directive with the value of "/tmp/.sock" should be modified to match the .sock we specified in the railsapp1.com configuration file located at /etc/nginx/sites-available/railsapp1.com.

We'll quickly examine the contents of the railsapp1.com configuration using the head command. (Alternatively, you can just open the file in your text editor).

$ head -n 10 /etc/nginx/sites-available/railsapp1.com

##############################################################
# Upstream must have unique name and unique socket.          #
# The socket must match what is in the app's unicorn.rb file #
##############################################################
upstream railsapp1_server {
  server unix:/tmp/railsapp1.sock fail_timeout=0;
}

##############################
# Rewrite www to non-www     #

From this, we see that the line in the config/unicorn.rb should be

listen "/tmp/railsapp1.sock", :backlog => 64

You can name your sockets whatever you want, just make sure they match between the upstream of your nginx conf and the listen directive in your unicorn.rb file and are unique to other apps!.

Now the next listen directive specifies a port unicorn will run on. This number does not need to be specified anywhere in the nginx configuration files, so just check to make sure that this number is unique between your apps in their config/unicorn.rb files. The current port specified should be 8080, and we can leave it that way.

Now, repeat the process for the railsapp2.com site. The only thing you need to do differently is ensure you specify a port number other than 8080 and greater than 1024. (Ports below 1024 require root privileges).

The Fruits of Your Labor

It's been a long journey, but now we are finally ready to unveil the fruits of your labor!

First, restart nginx and start the unicorn processes.

$ restart_nginx
$ cd /var/www/railsapp1.com/current
$ start_unicorn
$ cd /var/www/railsapp2.com/current
$ start_unicorn

Visit the following URLs in your browser:

http://www.railaspp1.com/pages/show
http://www.railaspp2.com/pages/show

These pages should have different text, verifying that nginx has properly routed these requests to different apps despite being on the same server.

HORRAY!!!!