NGINX regular expression to match location with optional parameter - nginx

I like to match location with two optional parameters so it it matches
/images/my.jpg
/images/my.jpg/200
/images/my.jpg/200/
/images/my.jpg/200/400
/images/my.jpg/200/400/
I am using three match groups so that I can get the matched part in $image, $width and $height variables.
I tried this query. It works only if the full location is given but it does not match if one of the parameter is missing
~ ^/images/(?<img>.+?)/(?<width>\d+)/(?<height>\d+)?$
I also tried which does not work at all
~ ^/images/(?<img>.+?)?(/?<width>\d+)?(/?<height>\d+)?$
please help - I have input data here. https://regex101.com/r/qU7tI7/6
nginx config here
server {
listen 80;
server_name f.myhost.com;
set $sitename f.myhost.com;
root $root_folder/myhost.com/files;
set $path_info "";
location / {
root /var/www/myhost.com/app/api/;
include conf.d/site.template;
add_header X-test "root";
}
location /files {
root /var/www/myhost.com/app/;
include conf.d/site.template;
}
location ~ ^/images/(?<img>[^/]+)(/(?<width>\d*))?(/(?<height>\d*))?$ {
# root /var/www/myhost.com/files/;
alias /var/www/myhost.com/app/test/$image;
# include conf.d/site.template;
add_header X-test "test";
add_header X-width "$width";
add_header X-height "$height";
add_header X-name "$image";
image_filter resize $width -;
image_filter_jpeg_quality 75;
image_filter_buffer 8M;
}
}

Try to try the following regular expression:
/^(\/images\/)([\da-z\.-]+\.[a-z\.]{2,6}|[\d\.]+)\/(\d+)\/(\d+)?$/igm

Related

replace part of request_uri before passing it to proxy_pass

i'm trying to replace specific part or request_uri using rewrite, but it won't work for some reason
example url: http://example.com:3000/?soft=55191&src1=changethis&src2=HOME&type=0&id=7700458
server {
server_name example.com;
listen 3000;
location / {
resolver 8.8.8.8;
rewrite ^(?<=&src1=)(.*)(?=&src2)$ changewiththis$1 break;
proxy_pass http://example2.com;
}
}
so the Goal here is to replace the exact string between 'src1=' and '&src2' so it can be passed to proxy_pass with the changed string
The location and rewrite directives use a normalised URI which does not include the query string (anything from the ? onwards).
To manipulate the query string, you will need to look at the $request_uri or $args variables, or the individual parameters using the $arg_ family of variables (e.g. $arg_src1).
The simplest solution may be to use a map directive to manipulate $request_uri before passing the new value upstream.
For example:
map $request_uri $changethis {
default $request_uri;
~(?<prefix>.*[?](|.*&)src1)=[^&]*(?<suffix>.*)$ $prefix=newvalue$suffix;
}
server {
...
location / {
resolver ...;
proxy_pass http://example.com$changethis;
}
}
See this document for details.

Disable logging for specific useragent in nginx conf

I want to disable logging for a specific useragent. This is a part of my current conf-file.
if ($http_user_agent ~ (bingbot|AhrefsBot|DotBot|Exabot|Baiduspider|SemrushBot) ) {
return 403;
}
I've tried adding access_log off; but get the following error:
nginx: [emerg] "access_log" directive is not allowed here
I'm assuming this is because I only have a server block. I need a location block also. I've tried the following code:
location / {
if ($http_user_agent ~ (bingbot|AhrefsBot|DotBot|Exabot|Baiduspider|SemrushBot) ) {
return 403;
}
}
But I get the following error:
duplicate location "/"
In my conf-file I already have this code:
location / {
try_files $uri $uri/ =404;
}
Can I combine the two location snippets into one? Or how do I proceed?
As your question indicates, the access_log directive cannot be used within an if block unless enclosed within a location. However, the access_log directive does include an if=condition which can be controlled by a map. There is an example at the end of this section of the manual.
For example:
map $http_user_agent $goodagent {
default 1;
~(bingbot|AhrefsBot|DotBot|Exabot|Baiduspider|SemrushBot) 0;
}
server {
access_log ... if=$goodagent;
if ($goodagent = 0) { return 403; }
...
}
The map directive must be placed outside of the server block. The access_log statement can be placed inside or outside the server block depending on whether it applies to all server blocks or just one.
At the http level declare a map like so.
map $http_user_agent $ignore_status_checks {
default 0;
"~Pingdom.*" 1;
"~*\(StatusCake\)" 1;
"~*mod_pagespeed*" 1;
"~*NodePing*" 1;
}
Then in your server's location block add:
if ($ignore_status_checks) {
access_log off;
}
This will turn off the access_log for anything returns a 1 in the map. Of course, you can do want ever you want in the if.

How to make map-derived variable reflect the current $uri?

A request for /olddir1/img.jpeg using the following nginx configuration will do a correct internal redirect to /newdir1/img.jpeg but it will leave the variable $extra_uri set to the value it would have during the first rewrite cycle, that is /olddir1/img.jpeg.
Just before executing the rewrite directive, $alias_uri and $extra_uri will have the following values, all correct:
$alias_uri: /newdir1/img.jpeg
$extra_uri: /olddir1/img.jpeg
After the rewrite directive is run, setting $uri to /newdir1/img.jpeg, the variables will have the following values:
$alias_uri: /newdir1/img.jpeg
$extra_uri: /olddir1/img.jpeg
$alias_uri has the correct value (nothing has matched in the map, so the default is being used, i.e. the current $uri). $extra_uri instead has a stale value.
How come $extra_uri isn't set to the new $uri?
server {
listen 80 default_server;
server_name 'test.example.local';
location / {
root '/var/www/test/content';
set $alias_uri $example__alias_uri;
set $extra_uri $example__extra_uri;
if ($alias_uri != $uri) {
rewrite ^ $alias_uri last;
}
add_header X-Alias "uri: >$uri< alias_uri: >$alias_uri<" always;
add_header X-Extra "uri: >$uri< extra_uri: >$extra_uri<" always;
try_files $uri =404;
}
map $uri $example__alias_uri {
default $uri;
~/olddir1(?<file>/[^/]*)$ /newdir1$file;
~/olddir2(?<file>/[^/]*)$ /newdir2$file;
}
map $uri $example__extra_uri {
default $uri;
}
Marking the maps as volatile makes this problem go away.
map $uri $example__alias_uri {
volatile;
default $uri;
~/olddir1(?<file>/[^/]*)$ /newdir1$file;
~/olddir2(?<file>/[^/]*)$ /newdir2$file;
}
map $uri $example__extra_uri {
volatile;
default $uri;
}
It seems that maps are evaluated only once during the very first rewrite phase and never afterwards.

Nginx proxy pass and url rewriting

How to trig this rule only when I have GET parameters(query string) in url,
otherwise I will match on an alias.
location ~^/static/photos/.* {
rewrite ^/static/photos/(.*)$ /DynamicPhotoQualitySwitch/photos/$1 break;
expires 7d;
proxy_pass http://foofoofoo.com;
include /etc/nginx/proxy.conf;
}
The 1st way that I know of is using a regex against the $args parameter like so:
if ($args ~ "^(\w+)=") {
Or the 2nd way is to use the convenient $is_args like so:
if ($is_args != "") {
Remember that in both styles you need to put a space between the if and the opening parenthesis; "if (" not "if(" as well as a space after the closing parenthesis and the opening brace; ") {" rather than "){".
Full example using the 1st style above, nginx.conf:
location ~^/static/photos/.* {
include /etc/nginx/proxy.conf;
if ($args ~ "^(\w+)=") {
rewrite ^/static/photos/(.*)$ /DynamicPhotoQualitySwitch/photos/$1 break;
expires 7d;
proxy_pass http://foofoofoo.com;
}
}
Full example using the 2nd style above, nginx.conf:
location ~^/static/photos/.* {
include /etc/nginx/proxy.conf;
if ($is_args != "") {
rewrite ^/static/photos/(.*)$ /DynamicPhotoQualitySwitch/photos/$1 break;
expires 7d;
proxy_pass http://foofoofoo.com;
}
}
Note that the proxy.conf include goes outside of the if statement.
Version:
[nginx#hip1 ~]$ nginx -v
nginx version: nginx/1.2.6
And some info on the $args and $is_args variables:
http://nginx.org/en/docs/http/ngx_http_core_module.html
Reading the docs is always useful, I just discovered that $query_string is the same as $args, so where I have $args above, you could also use $query_string according to the docs.
IMPORTANT
It is important to note however, that If can be Evil!
And therefore either test thoroughly or use the recommendation provided in the link above to change the URL inside location statement in a way similar to the example provided there, something like:
location ~^/static/photos/.* {
error_page 418 = #dynamicphotos;
recursive_error_pages on;
if ($is_args != "") {
return 418;
}
# Your default, if no query parameters exist:
...
}
location #dynamicphotos {
# If query parameters are present:
rewrite ^/static/photos/(.*)$ /DynamicPhotoQualitySwitch/photos/$1 break;
expires 7d;
include /etc/nginx/proxy.conf;
proxy_pass http://foofoofoo.com;
}

nginx: auth_basic for everything except a specific location

How can I enable HTTP Basic Auth for everything except for a certain file?
Here is my current server block configuration for the location:
location / {
auth_basic "The password, you must enter.";
auth_basic_user_file /etc/nginx/htpasswd;
}
location /README {
auth_basic off;
}
However, on /README, it is still prompting for a password.
How can we fix this?
Thanks!
Mark
Try to use sign = , that helps you:
location = /README {
auth_basic off;
allow all; # Allow all to see content
}
I am doing something similar using "map" instead of "if" to assign the auth_basic realm variable and htpasswd file:
map $http_host $siteenv {
default dev;
~^(?<subdomain>.+)\.dev dev;
~^(?<subdomain>.+)\.devprofile devprofile;
~^(?<subdomain>.+)\.devdebug devdebug;
~^(?<subdomain>.+)\.test test;
~^(?<subdomain>.+)\.demo demo;
~^(?<subdomain>.+)\.stage stage;
# Live
~^(?<subdomain>.+)\.live live;
~^.*\.(?P<subdomain>.+)\.[a-zA-Z]* live;
}
map $http_host $auth_type {
default "Restricted";
~^(?<subdomain>.+)\.dev "Development";
~^(?<subdomain>.+)\.devprofile "Development";
~^(?<subdomain>.+)\.devdebug "Development";
~^(?<subdomain>.+)\.test "Testing";
~^(?<subdomain>.+)\.stage "Stage";
~^(?<subdomain>.+)\.demo "Demo";
# Live
~^(?<subdomain>.+)\.live "off";
~^.*\.(?P<subdomain>.+)\.[a-zA-Z]* "off";
}
server {
.. etc ..
auth_basic $auth_type;
auth_basic_user_file /etc/nginx/conf.d/htpasswd-$siteenv;
}
I'm doing the following:
location = /hc.php {
auth_basic "off";
}
location / {
try_files $uri $uri/ =404;
}
The narrow match:location = /somefile.txt {} comes first, so location / {} can capture the remaining requests
auth_basic "off" requires the quotes around it as far as I know
I also use the exact (full, if you like) match, in order to stop iteration over the other locations defined in the config (read below quote for more info on what it does)
Probably this would work in different orders, and/or without the double quotes also, but why not try to do things as correct and complete as possible, if possible.
The most important modifiers are:
(none) No modifier at all means that the location is interpreted as a prefix. To determine a match, the location will now be matched against the beginning of the URI.
=: The equal sign can be used if the location needs to match the exact request URI. When this modifier is matched, the search stops right here.
~: Tilde means that this location will be interpreted as a case-sensitive RE match.
~*: Tilde followed by an asterisk modifier means that the location will be processed as a case-insensitive RE match.
^~: Assuming this block is the best non-RE match, a carat followed by a tilde modifier means that RE matching will not take place.
quoted from here: https://www.keycdn.com/support/nginx-location-directive
Only auth_basic off didn't work for me
If we have to skip auth for ALL uri's under our url
location ^~ /some/location/to_skip/ {
auth_basic off;
try_files $uri $uri/ /index.html;
}

Resources