Why do the following rules conflict in NGINX? - nginx

I have these two rules :
location ~* ^.+\.(jpg|jpeg|gif|css|js|png)$ {
proxy_pass http://127.0.0.1:44843$request_uri;
}
location /pc {
proxy_pass http://127.0.0.1:12345$request_uri;
}
The URI :
/pc/asser/somefile.js
falls in teh second rule, why ?
is it a question of lower priority of the "location /pc" rule ?

Nginx documentation defines it:
Directives are processed in the following manner:
Exact string matches are processed first. If a match is found, nginx stops searching and fulfills the request.
Remaining literal string directives are processed next. If the "^~" argument is used, then ngnix stops here and fulfills the request. Otherwise, nginx continues to process location directives.
All location directives specified by regular expressions (with the ~ and ~* arguments) are processed. If a regular expression matches the request, nginx stops here and fulfills the request.
When there are no regular expressions, or no regular expressions match, the most specific literal string match is used.
So you should use regular expression for /pc too:
location ~ /pc/.* {
proxy_pass http://127.0.0.1:12345$request_uri;
}

At first nginx check locations defined using the prefix strings (prefix locations).
And only after, it checks locations defined using regular expressions, in the order of their appearance in a configuration file.

http://nginx.org/en/docs/http/ngx_http_core_module.html#location specifies the order in which nging location directives are looked at:
To find a location matching a given request, nginx first checks locations defined
using the prefix strings (prefix locations). Among them, the most specific one is
searched.
Basically the problem here is that prefix locations are always given priority over regex ones
So in your config, if both blocks match, it's the /pc prefix one that gets priority

Related

Rewrite one specific argument with nginx rewrite

I want to rewrite an argument given via URL on my nginx server from "my_arg" to "my-arg". The problem is that I can't know how many arguments there will be in advance nor the position of these arguments.
I can only know if the arguments is there using :
if ($args ~ (.*)my_arg=(.*)) {
rewrite ....
}
But i cannot achieve to only change the name of this argument without changing every others.
Thanks by advance
For anything except HTTP 301/302 redirection you'd better just change an $args variable value:
if ($args ~ (^|.*&)my_arg=(.*)) {
set $args $1my-arg=$2;
}
If you want to generate a redirect, things will be more complicated. Since any rewrite directive performs its own URI matching against some regex pattern, all the $1, $2 and so on variables from previous matching will be overwritten, and you can't match a query part of the URI to get them re-evaluated since rewrite directive works with normalized URI that doesn't include a query part. Your only way is to use named capture groups:
if ($args ~ (?<prefix>^|.*&)my_arg=(?<suffix>.*)) {
rewrite ^ $uri${prefix}my-arg=$suffix? <redirect|permanent>;
}
Trailing question mark used intentionally since as rewrite directive documentation says,
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended, for example:
rewrite ^/users/(.*)$ /show?user=$1? last;

Rewrite url without hash in nginx

I am trying to use Nginx rewrite static file path to strip the hash added for cache busting. The hash is always 10-symbol long. For example,
/min/3rd.party.min.1234567899.js has to become /min/3rd.party.min.js
I have tried this, but it doesn't work (fails at configtest) and also looks way to complicated.
location /min/ {
root /opt/app/public;
rewrite ^.*(?<=(.))[a-z0-9]{10}[.](?=(js|css))[js|css]$ $1$3;
}
I have no idea how you arrived at your regular expression pattern, but the following seems to work:
rewrite "^(.*)\.\w{10}\.(js|css)$" $1.$2 break;
Any pattern that contains a brace, must be placed within quotes. Use the break suffix to process the rewritten URI within the same location. See this document for details, and this useful resource on regular expressions.

Nginx rewrite anything after specific keyword

I want to rewrite all requests after "whois" keyword in url to whois.php in nginx but can't find suitable rules.
e.g. rewrite domain.com/whois.php/TEST.COM to whois.php?domain=TEST.COM.
There are a number of options available to you. One solution is:
location ~* ^/whois.php/ {
rewrite ^(/whois.php)/(.*)$ $1?domain=$2 last;
}
Place the location block above other regex locations that might match, as regex locations are executed on the basis of the first one that matches.
See this and this for more.

How do I restric access with nginx location to url matching an expression with a string and a number?

I have the following path as a Nginx Location :
/api/users
The url that my users access is /api/users?id=109238717283223
The problem is I don't want the direct path /api/users to be accessible, and the goal is to allow access only when the url contains users?id=number(with exact amount of digits)
How could I achieve this with a regex ?
Individual arguments can be accessed using the $arg_ variable prefix. It can be tested against a regular expression using an if directive. For example, an exact match location that ensures that the id parameter is exactly 15 digits:
location = /api/users {
if ($arg_id ~ ^\d{15}$) { return 403; }
...
}
Read this documentation regarding limitations using the if directive.

how to match # character in a url in nginx through location directive

How do I match a # character in a url using location directive? I understand that we can use regex(PCRE), but their docs say that :
The location directive only tries to match from the first / after the hostname, to just before the first ? or #. (Within that range, it matches the unescaped url.)"
In short, How to match "example.com/#123456" using
location ~ [someregex] {
return 200 "matched";
}
or with any other alternative
Simple answer, you can't actually, because that part is never sent to the server to begin with, the only way to process this is to use Javascript, using location.hash
You can't because the ID hash isn't actually sent to the server, you might want to use GET variables like example.com?p=1234 if you intend to direct to a certain page or use location.hash if you wish to direct to a location on the page (which is its intended use)
Good luck!

Resources