Nginx location with regex in the middle of path - regex

i'm trying to configure Nginx to parse correctly two similar paths with a regex in it.
I have 2 services:
/api/v1/myservice/{var}/client
/api/v1/myservice/{var}/client/detail
{var} is a variable I'm reading which is working
Here my code (not using the var here):
location ~ /api/v1/myservice/(.*)/client {
return 200 "service 1 ";
}
location ~ /api/v1/myservice/(.*)/client/detail {
return 200 "service 2";
}
When I run curl like the following:
curl http://localhost/api/v1/myservice/623723852/client/detail
I see the response from the first location:
"Service 1"
What Am I doing wrong?
thanks

No need to have nested locations as in the other answer. The nested locations in NGINX often give a false impression about directives' inheritance. More often than not, they are not inherited, because NGINX chooses one specific location anyway. For these reasons, if you can, avoid nested locations.
You can simply change the order of locations so that the more specific one goes first. NGINX will match the one that appears first in the config (if they both match):
location ~ /api/v1/myservice/(.*)/client/detail {
return 200 "service 2";
}
location ~ /api/v1/myservice/(.*)/client {
return 200 "service 1 ";
}
Alternatively, somewhat better (for performance reasons), you can adjust your regexes for more exact matching. Then the placement in configuration won't matter:
location ~ ^/api/v1/myservice/(.*)/client$ {
return 200 "service 1 ";
}
location ~ ^/api/v1/myservice/(.*)/client/detail$ {
return 200 "service 2";
}

Related

Regex to redirect two different URLs starting with the same string

Those are my two nginx rules :
rewrite ^(/v1/foobar)(.*)$ /final$2 permanent;
rewrite ^(/v1/foobar-tow)(.*)$ /final$2 permanent;
I expect that /v1/foobar-two/foo will use the second rule and then will redirect to /final/foo but I doesn't : since the URL starts with foobar, the first rule will be used and finally will redirect to final-two/foo : the concatenation of the first target and the difference between the first and second rule !
To solve the problem I've just inversed the rules, but I wonder if there is a better solution !
To sum up, this is what I'm looking for :
/v1/foobar -> /final
/v1/foobar/hello -> /final/hello
/v1/foobar-tow -> /final
/v1/foobar-tow/hola -> /final/hola
To avoid surprises with NGINX, and increase configuration scalability, you should, generally:
try to live without rewrite directive; as per NGINX author it simply appeared before location and in many cases you can now use location with capture groups in lieu of rewrite
design your regular expressions in the way that the order of matching is not important, if possible
use exact matching, where applicable
isolate regular expression locations under a prefixed one
Putting all things together:
location /v1/ {
location = /v1/foobar {
return 301 /final;
}
location ~ ^/v1/foobar/(\w+)$ {
return 301 /final/$1;
}
location = /v1/foobar-tow {
return 301 /final;
}
location ~ ^/v1/foobar-tow/(\w+)$ {
return 301 /final/$1;
}
}

Nginx regex to match single path

Suppose I have these paths:
/
/something # this path is variable (any characters except /)
/api/v1/something
What is the best nginx config to capture this requirement? The following is not working for m:
server {
listen 8080;
location ~^/(?:.*)$ {
...
}
location / {
...
}
location /api/v1/something {
...
}
}
Your regular expression matches everything which means it always wins! See the documentation to understand how Nginx chooses which location block to process a request.
You do not need to use a regular expression location.
First define location blocks for the single URIs using the = operator:
location = / { ... }
location = /api/v1/foo { ... }
Then use the default location to catch anything else:
location / { ... }
The above location blocks can appear in any order. Only regular expressions are sensitive to evaluation order.

nginx location regex rule not working

We are trying to create a location rule on nginx side, but its not working as expected. Below is the location rule
location ~* ".*\.legalcontent\.html\?path=\/legal\/.*" {
return 200 'regex rule'; //Using this temporarily to confirm if rule is triggering
}
Incoming URL is below, want to capture (.legalcontent.html?path=/legal/)
https://www.mycompany.com/myapp/myproduct/mysubpage.legalcontent.html?path=/legal/somepage
Tested regex separately on regex tool, seems to be good
But its not working, tried simple context roots to check if everything else is good.
# Following simple rules works fine, but we want location to kick-in
# only for specific condition
location /myapp {
return 200 'myapp rule';
}
location /myapp/myproduct {
return 200 'myapp myproduct rule';
}
Is there a way to handle location rule for this kind of input URL
The location will only check the path of the request. To check the arguments you must create a conditional with the $args variable.
location ~* ".*\.legalcontent\.html$" {
if ($args ~* "^path=\/legal\/.*") {
return 200 'regex rule';
}
}

nginx remove / rewrite GET Parameters for specific URL

I want to create a nginx localtion do to the following
Given URL:
example.com/foo/bar/123456?ItemID=123456&aid=0&bid=0
Task:
If both numbers are the same and aid and bid are zero, then rewreite the url to example.com/foo/bar/123456
My Try:
location ~ ^/foo/bar/(?<prid>\d+)\?ItemID=\1&aid=0&bid=0$ {
rewrite ^ /foo/bar/$prid? permanent;
}
But that doesn't work. ;)
Would be great if s.o. could give me a hint.
EDIT:
nginx seems not to match GET-Parameters by regex at all (in location line) so you have to use $args and check with if (which can be evil according to documentation).
This should work:
location ~ /foo/bar/(\d+) {
if ($arg_ItemID = $1) { set $check I; }
if ($arg_aid = 0) { set $check "${check}A"; }
if ($arg_bid = 0) { set $check "${check}B"; }
if ($check = IAB) {
rewrite ^ /foo/bar/$arg_ItemID? permanent;
} }
Explanation:
nginx doesn't include the parameters in the match for rewrite. You can access the parameters by name via $arg_name.
the set of if-statements is a work-around (described here), because nginx doesn't allow multiple conditions
the ? at the end of the replacement cuts off the arguments from the original request

NGINX: check whether $remote_user equals to the first part of the location

I can't figure out how to configure the check whether $remote_user equals to the first part of the location.
location / {
auth_basic "ElasticSearch";
auth_basic_user_file /etc/nginx/search_passwords;
location ~/([^/]*)/ { # named capture did not work either
if ($remote_user = $1) { # ERROR: Unknown variable: $1 / $NAMEDWHATEVER
break;
}
}
}
My use-case:
I am trying to "secure" an ElasticSearch-Cluster by using a nginx-reverse proxy for authentication. I want to allow multiple users, but the modifications for a new user should be as simple as possible; best case - just change the htpasswd-file.
I'm trying to adopt the nginx-elasticsearch-proxy but fail to check whether remote_name and index-name are equal.
It should be possible and you can also define a name of a variable when matching with regex.
Here in the code fragment below, I assign the result of the regex to the variable $username. Then I can check it and if matching the $remote_user (be sure that this one is correctly set, in case just debug it as I did) then I added an extra header to the response so you can see it with the Firebug network console or just by using the curl command .
Have a look to see if this one helps you.
location / {
auth_basic "ElasticSearch";
auth_basic_user_file /etc/nginx/search_passwords;
location ~ /(?<username>([^/]*))/ { # capture and store in the username variable
if ($remote_user = $username ) {
add_header 'matched' 'true $username';
break;
}
}
}
See also this How to I get variables from location in nginx? for more info.