Nginx configuration for multiple Rails apps

Nginx is a popular web server for Rails apps. Typically you’d have one Nginx file per application. However, you may want to run multiple Rails apps on a single server, for rapid prototyping. In this case, you can make do with a single Nginx file.

Here’s an example nginx.conf file that runs two Rails applications, app1 and app2. Both apps are using Puma as an app server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
http {
  upstream app1 {
    server unix:/var/www/app1/current/tmp/sockets/puma.sock fail_timeout=0;
  }

  upstream app2 {
    server unix:/var/www/app2/current/tmp/sockets/puma.sock fail_timeout=0;
  }

  server {
    listen 80;
    server_name app1.com

    root /var/www/app1/current/public;

    location / {
      proxy_pass http://app1;
    }
  }

  server {
    listen 80;
    server_name app2.com

    root /var/www/app2/current/public;

    location / {
      proxy_pass http://app2;
    }
  }
}

Let’s step through each part to understand how it works.

Upstream blocks

upstream is an Nginx directive used to define servers. In this case, we’re defining two serves: app1 and app2.

Inside the upstream block is a server directive that defines the address of the two app servers. In this case, it’s a UNIX socket connection to a running puma process.

Server blocks

Next, we have two server blocks, one for each app. Both server blocks have the same logic, here’s how they work:

listen

The first line uses the listen directive to listen on port 80. If you want to run apps over https then you’d need to change listen to port 443 and define your SSL certs.

server_name

The next line defines server_name. It’s used by Nginx to look up which server block to run. It does this using the Host header, sent by the browser.

root

root specifies the root directory, from which Nginx will search for other relative files. This should point to the Rails root directory.

Location block

Lastly, there is a location block. This block specifies / which means it matches any URI (given there are no other location blocks defined). It then proxies the request to the upstream server (app1 or app2) using proxy_pass. This is how Nginx connects to Puma.

Further improvements

It’s worth noting that, although this setup works, it doesn’t scale well. Managing many applications would be difficult - it would become a single file of spaghetti code. If you intend to scale this up past 2-3 sites, we recommend creating separate config files in sites-available.