nginxnginx-locationnginx-confignginx-log

Location not working for files but only for path


I have a nginx.conf that looks like this:

server {
  ...
  root /var/opt/data/web;
  ...

  location ~* \.(?:eot|woff|woff2|ttf|js)$ {
    expires 1M;
  }

  ...

  location /one {
    root /var/opt/data/alternatives;
    try_files $uri $uri/ =404;
  }

  location /two {
    root /var/opt/data/alternatives;
    try_files $uri $uri/ =404;
  }
}

when I curl http://localhost/one/ I get the content of index.html stored in /other. But when I curl .../localhost/one/foo.js the file is not found and I get this in the error.log:

open() "/default/foo.js" failed (2: No such file or directory)

I tried other variants like location ~ (one|two), location /one/ or even location ~ /(one|two) but all of them didn't work.

The complete config consists of a lot more locations, but I guess the cause of my problem is the location where I set up .js resources to expire -1 because this prevents changing the root to what I need.

If this matters: I use nginx 1.15.2. In case you are wondering why I have this strange alternatives directory: the web directory is created by a CMS software while alternatives is git pulled.


Solution

  • nginx chooses a one location to process a request. Your location ~* \.(?:eot|woff|woff2|ttf|js)$ block processes any URI that ends with .js, and its root value is inherited from the outer block as /var/opt/data/web.

    Where you have multiple roots, you need to ensure that those location blocks take precedence, by using the ^~ modifier. See this document for details.

    For example:

    server {
        ...
        root /var/opt/data/web;
        ...    
        location ~* \.(?:eot|woff|woff2|ttf|js)$ {
            expires 1M;
        }    
        ...
        location ^~ /one {
            root /var/opt/data/alternatives;
            try_files $uri $uri/ =404;
    
            location ~* \.(?:eot|woff|woff2|ttf|js)$ {
                expires 1M;
            }    
        }
        ...
    }
    

    If you need your expires rule to apply to the other roots, you will need to repeat the location within that scope, as shown above.


    As an alternative, the expires directive can be used in conjunction with a map. See this document for details.

    For example:

    map $request_uri $expires {
        default                            off;
        ~*\.(eot|woff|woff2|ttf|js)(\?|$)  1M;
    }
    server {
        ...
        root /var/opt/data/web;
        expires $expires;
        ...
        location ^~ /one {
            root /var/opt/data/alternatives;
            try_files $uri $uri/ =404;
        }
        ...
    }