262

How can I have same rule for two locations in NGINX config?

I have tried the following

server {
  location /first/location/ | /second/location/ {
  ..
  ..
  }
}

but nginx reload threw this error:

nginx: [emerg] invalid number of arguments in "location" directive**
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
nothing_authentic
  • 2,927
  • 3
  • 17
  • 22

5 Answers5

379

Try

location ~ ^/(first/location|second/location)/ {
  ...
}

The ~ means to use a regular expression for the url. The ^ means to check from the first character. This will look for a / followed by either of the locations and then another /.

phoenix
  • 7,988
  • 6
  • 39
  • 45
curtwphillips
  • 5,441
  • 1
  • 20
  • 19
  • 70
    NOTE: if this occurs often (like thousands), it will incur a performance penalty due to regex matching. Also the order of matching is substantially different. In a lot of "small" cases, it will behave like you want, but this is something to stay aware of. I personally want Nginx "location" to support multiple "=" conditions instead of relying on a regex rule. – Bernard Dec 05 '16 at 19:02
  • 11
    IMHO, this should be more efficient: location ~ (patternOne|patternTwo){ ... } – stamster Jan 17 '17 at 18:26
  • 2
    This solution did not work for me; however @stamster's comment did; I'm running `nginx/1.13.2` – TJ Biddle Jul 07 '17 at 23:33
  • 4
    if you need `proxy_pass` to work, see this answer: https://stackoverflow.com/a/46625656/1246870 – avs099 Jun 01 '19 at 01:33
  • 4
    This does not work for me when original URL ends with no slash – The Godfather Jul 15 '19 at 16:41
  • @TheGodfather You have to add `\/?` at the end of the regex – Ahmed Shaqanbi May 09 '22 at 11:35
  • regex for nginx: https://stackoverflow.com/a/59846239 – djvg Jun 16 '23 at 11:03
131

Another option is to repeat the rules in two prefix locations using an included file. Since prefix locations are position independent in the configuration, using them can save some confusion as you add other regex locations later on. Avoiding regex locations when you can will help your configuration scale smoothly.

server {
    location /first/location/ {
        include shared.conf;
    }
    location /second/location/ {
        include shared.conf;
    }
}

Here's a sample shared.conf:

default_type text/plain;
return 200 "http_user_agent:    $http_user_agent
remote_addr:    $remote_addr
remote_port:    $remote_port
scheme:     $scheme
nginx_version:  $nginx_version
";
Cole Tierney
  • 9,571
  • 1
  • 27
  • 35
71

Both the regex and included files are good methods, and I frequently use those. But another alternative is to use a "named location", which is a useful approach in many situations — especially more complicated ones. The official "If is Evil" page shows essentially the following as a good way to do things:

error_page 418 = @common_location;
location /first/location/ {
    return 418;
}
location /second/location/ {
    return 418;
}
location @common_location {
    # The common configuration...
}

There are advantages and disadvantages to these various approaches. One big advantage to a regex is that you can capture parts of the match and use them to modify the response. Of course, you can usually achieve similar results with the other approaches by either setting a variable in the original block or using map. The downside of the regex approach is that it can get unwieldy if you want to match a variety of locations, plus the low precedence of a regex might just not fit with how you want to match locations — not to mention that there are apparently performance impacts from regexes in some cases.

The main advantage of including files (as far as I can tell) is that it is a little more flexible about exactly what you can include — it doesn't have to be a full location block, for example. But it's also just subjectively a bit clunkier than named locations.

Also note that there is a related solution that you may be able to use in similar situations: nested locations. The idea is that you would start with a very general location, apply some configuration common to several of the possible matches, and then have separate nested locations for the different types of paths that you want to match. For example, it might be useful to do something like this:

location /specialpages/ {
    # some config
    location /specialpages/static/ {
        try_files $uri $uri/ =404;
    }
    location /specialpages/dynamic/ {
        proxy_pass http://127.0.0.1;
    }
}
Mike
  • 19,114
  • 12
  • 59
  • 91
  • NOTE: the "alias" directive cannot be used inside the named location. – Sergio Cabral Nov 24 '20 at 10:24
  • 1
    It would be nice to add an explanation over the return 418 error_page, it's a bit confusing, but basically this is using error pages as a goto block, the 418 error code being the 'It's a teapot' joke it is one of the few safe codes to use – Tofandel Nov 24 '20 at 10:51
  • Not sure if the last approach is actually working. I've tried to add one directive to sublocation without success. ``` location / { set $var $dir/app.sock:$request_uri; include common_conf; location /foo { # 404 at result =( proxy_request_buffering off; } } ``` – re-gor Feb 16 '23 at 14:17
16

This is short, yet efficient and proven approach:

location ~ (patternOne|patternTwo) {
    #rules etc.
}

So one can easily have multiple patterns with simple pipe syntax pointing to the same location block / rules.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
stamster
  • 953
  • 11
  • 18
  • 1
    This answer is a duplicate of https://stackoverflow.com/a/35369570/254343, I don't know why people don't read answers before writing their own – Armen Michaeli Dec 15 '22 at 19:24
0

This worked for me

upstream nextjs-fp {
  server  nextjs-frontend:3000;
}

server {
  listen 80;
  
  location ~* .(_next|profile|orders)$  {
    proxy_pass http://nextjs-fp;
  }
  
}
Nishan B
  • 627
  • 7
  • 11