nginx location regex rule not working - regex

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';
}
}

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.

supporting deep-linking with location regex and try_files, can't redirect to foo/local/ to foo/index.html

I have a number of drop in GUIs that all under the general TTP subdomain and all allow deep-linking. Specifically the URL /TTP/app/site/ should load GUI named app with site's statistics. with /ttp/app loading the same GUI with the default site.
This should work by redirecting both /ttp/app and /ttp/app/site/ requests to the /usr/share/html/ttp/app/index.html page, that page will parse the remaining url and figure out which backed to hit if site is provided.
Currently I have something like this in my conf file (I'm utilizing the nested location for other things not included here):
location /ttp {
root /usr/share/nginx/html/ttp/;
location ~ ^/foo/ {
try_files $uri $uri/ /foo/index.html;
}
location ~ ^/bar/ {
try_files $uri $uri/ /bar/index.html;
}
... (one for each app)
}
This works, but is redundant. I'm trying to consolidate this with a regex which will cover all apps with a single location. I've tried a few variants, original having issue with greedy regex grabbing all /app/site/ instead of just /app/. My best attempt with non-greedy regex being
location /ttp {
index index.html
root /usr/share/nginx/html/ttp/
location ~ ^/((?U).*)/ {
try_files $uri /$1/index.html;
}
}
this give me an error about rewrite or internal redirection cycle while internally redirecting ti "/ttp/index.html" Which seems to imply it's not greedy enough and is completely ignoring app with $1 being a null string.
Is there some clean way to do this, with regex or some directive I'm not aware of?
Your example is flawed - I presume you over simplified it and we are missing the part that removes the /ttp prefix after it enters the outer location block.
You have a URI structure /ttp/foo/xxx and you would like the default action to be /ttp/foo/index.html where foo is the name of an app.
You can use non-greedy regular expression, but you may find the [^/] character class easier to use for matching individual path elements in the URI.
If the final element of a try_files statement needs a rewrite, use a named location. See this document for more.
For example:
location /ttp {
root /usr/share/nginx/html;
try_files $uri $uri/ #rewrite;
}
location #rewrite {
rewrite ^(/ttp/[^/]+)/ $1/index.html last;
return 404;
}
Any URI of the form /ttp/foo/xxx that takes the default action, will re-enter the location /ttp block with the URI as /ttp/foo/index.html. The root parameter is prefixed to the URI to form the local path.

Nginx location match regex not working

I am unable to match location with below mentioned pattern, I want to set expires header to 24 hrs. but it is not working. It works if I just use below mentioned regex :
location ~* .*abc\.php.* {
expires 24h;
}
Below example does not work.
location ~* .*abc\.php.*xyz=detail.*login_something=.* {
expires 24h;
}
There is lot of content in between and after of "abc.php" & "xyz=detail" & "login_something=" so I have to use .* only.
Thanks in advance!
There are multiple ways to achieve what you are trying to do, but the simplest method is to apply your mega regex to a variable that contains the entire URI (including the query string). This would be $request_uri
The second problem is how to manipulate expires and again, rather than use multiple blocks and have to reimplement PHP directives in each one, just use the map directive as detailed in the expires documentation.
For example:
map $request_uri $expires {
default off;
~*abc\.php.*xyz=detail.*login_something= 24h;
}
server {
...
expires $expires;
...
}

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.