4

I'd like to use nginx in order to map all my rails apps on port 80.

Currently, I have 3 rails apps running on port 3000 3001 and 3002 and I'd like to use nginx on port 80 to map them so :

http://127.0.0.1/app1 => 127.0.0.1:3000
http://127.0.0.1/app2 => 127.0.0.1:3001
http://127.0.0.1/app3 => 127.0.0.1:3002

Here's what I did :

server {
    listen 80;
    location /app1/ {
        proxy_pass http://127.0.0.1:3000/;
    }

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

    location /app3/ {
        proxy_pass http://127.0.0.1:3002/;
    }
}

However, when I try to access http://127.0.0.1/app1, I only get the HTML content, no assets/js/css as the browser tries to get them from http://127.0.0.1/assets instead of http://127.0.0.1/app1/assets.

Is there a way to fix this?

2 Answers 2

1

Add ActionController::Base.relative_url_root = "/app1" to the end of your config/environment.rb of app1 (similarly for other two apps). This will make Rails add proper prefix to URLs.

If you don't want to mess with Rails config, you probably could force Nginx to go through all of your assets folder until it finds the one it needs, if I'm not mistaken it could be archived like this:

location /assets/ {
  try_files /app1/$uri /app2/$uri /app3/$uri;
}

Please note that you must have different filenames for assets of different apps. That is already so if you are using asset pipeline everywhere, as it hashes file names.

UPD.

You can also try 'Referer'-based routing:

location /assets/ {
   if ($http_referer ~* /app1) {
     rewrite ^(.*)$ app1/$1 break;
   }
   if ($http_referer ~* /app2) {
     rewrite ^(.*)$ app2/$1 break;
   }
   if ($http_referer ~* /app3) {
     rewrite ^(.*)$ app3/$1 break;
   }    
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, it works, but is there a way to achieve this without touching the rails app? In case I want to host a web app I can't modify?
Without changing Rails config it is not achievable. If it becomes a problem change only production config.
Well, I can see two ways to make that 'kinda' achievable: either mixing the assets in common /assets folder, or redirecting with nginx by looking at the 'Referer' header. Will update my answer with suggested work-around.
try_files among 3 different directories is anti-pattern, use config.assets.prefix and intercept it via Nginx location prefix
using multiple ifs inside a location context is a bad idea, as it has been documented several times. That series of if blocks should be rewritten with try_files.
|
1

This is a good default configuration for what you want to achieve:

server {
    listen 80;
    location /app1/ {
        root /srv/rails/app1/public;
        try_files $uri $uri/index.html $uri.html @app1_forward;
    }

    location @app1_forward {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app1_backend;
    }

    location /app2/ {
        root /srv/rails/app2/public;
        try_files $uri $uri/index.html $uri.html @app2_forward;
    }

    location @app2_forward {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app2_backend;
    }

    location /app3/ {
        root /srv/rails/app3/public;
        try_files $uri $uri/index.html $uri.html @app3_forward;
    }

    location @app3_forward {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app3_backend;
    }
}

upstream app1_backend {
    server 127.0.0.1:3000    fail_timeout=0;
}

upstream app2_backend {
    server 127.0.0.1:3001    fail_timeout=0;
}

upstream app3_backend {
    server 127.0.0.1:3002    fail_timeout=0;
}

Also check this article, where I link to this example nginx config, for Rails.

6 Comments

It is not full example, without pointing Rails assets directory to either of app1,app2,app3 it will not be working
It should work, but it will be inefficient. The links will point to a complere configuration file.
I don't understand how do you load an appropriate /assets/all.js for app1 for instance?
@Anatoly check this
I do know how to get Nginx serve multiple backend apps with single server block. What am I asking how do you distinct all.js between 3 different apps (3 different root directives) without additional Rails configuration config.assets.prefix? This directive designed to solve exact that problem.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.