1

I'm using Nginx on CentOS 7 with Ruby on Rails / Puma. I would like for certain file paths to be skipped by RoR and be served directly by Nginx. I created this in my "server" block for my site

location /assets/lib/ {
    alias /home/rails/myproject_production/app/assets/javascripts/lib/;
    autoindex off;
}

However, when I call an asset like http://www.mydomein.com/assets/lib/myfile.js, I get a 404. This is what appears in my logs

2018/05/11 15:21:47 [error] 242#0: *1 open() "/home/rails/myproject_production/public/assets/lib/myfile.js" failed (2: No such file or directory), client: 50.240.135.5, server: www.mydomein.com, request: "GET /assets/lib/myfile.js HTTP/1.1", host: "www.mydomein.com"

From the logs, it appears that the alias isn't being invoked at all. What am I missing in the above? My complete configuration is below

upstream myproject {
  server unix:///home/rails/myproject_production/shared/sockets/puma.sock;
}

# Listener for Apex Domain
server {
  listen 80;
  server_name www.mydomein.com;
  root /home/rails/myproject_production/public; # I assume your app is located at this location

  location / {
    proxy_pass http://myproject; # match the name of upstream directive which is defined above
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    if ($request_uri ~* "(\/image\/.*)|(.*\.(ico|gif|jpe?g|png)$)") {
      expires 60d;
      access_log off;
      add_header Pragma public;
      add_header Cache-Control "public";
      break;
    }
  }

  location /assets/lib/ {
        alias /home/rails/myproject_production/app/assets/javascripts/lib/;
        autoindex off;
  }

  location /cable {
    proxy_pass http://myproject;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }

  location ~* ^/assets/ {
    # Per RFC2616 - 1 year maximum expiry
    expires 1y;
    add_header Cache-Control public;

    # Some browsers still send conditional-GET requests if there's a
    # Last-Modified header or an ETag header even if they haven't
    # reached the expiry date sent in the Expires header.
    add_header Last-Modified "";
    add_header ETag "";
    break;
  }

}
Eddie C.
  • 535
  • 1
  • 3
  • 12
Dave
  • 185
  • 1
  • 7
  • 20

1 Answers1

1

You have two location blocks:

location /assets/lib/ {
  …
}
location ~* ^/assets/ {
  …
}

Now, as described in Nginx documentation, Nginx checks first prefix locations, and remembers longest match. Then it checks regular expression locations, and uses a matching block if found. If none is found, then it uses the prefix match.

So, in your case, nginx first finds the first location block, remembers it. However, the regular expression block also matches, and nginx selects that block.

In order to change nginx selection process, you need to use:

location ^~ /assets/lib {
  …
}

for your first location. It also means that the directives in the regular expression block are not applied to these requests.

Eddie C.
  • 535
  • 1
  • 3
  • 12
Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63