questions about $args on try_files inside location with regex - nginx

(sorry for my bad english)
i have a URL like this:
http://www.domain.com/resize.php?pic=images/elements/imagename.jpg&type=300crop
that php checks if that image exists and serves, if not, creates image on disk with the size specified in the type parameter and returns it.
what I wanted is to check if the image exists on disk at that size, with nginx, so run only resize.php when necessary to create the image.
I tried this, but i think that location directive doesn't operate on query parameters ($args) using regex, then loncation does not match with sample URL :(
any help please?
I need to rewrite the parameters ($args) and use them in the try_files directive... is this possible?
location ~ "^/resize\.php\?pic=images/(elements|gallery)/(.*)\.jpg&type=([0-9]{1,3}[a-z]{0,4})$)" {
try_files /images/$1/$2.jpg /imagenes/elements/thumbs/$3_$2.jpg #phpresize;
}
location #phpresize {
try_files $uri =404;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
proxy_pass http://www.localhost.com:8080;
}

You cannot match query string in location (e.g., see here and here). The only way to process requests differently depending on the query string contents is to use if and conditional rewrites.
However, if it is OK to handle requests to /resize.php which do not have expected query parameters using the #phpresize location config, you can try something like this:
map $arg_pic $image_dir {
# A subdirectory with this name should not exist.
default invalid;
~^images/(?P<img_dir>elements|gallery)/.*\.jpg$ $img_dir;
}
map $arg_pic $image_name {
# The ".*" match here might be insecure - using something like "[-a-z0-9_]+"
# would probably be better if it matches all your image names;
# choose a regexp which is appropriate for your situation.
~^images/(elements|gallery)/(?P<img_name>.*)\.jpg$ $img_name;
}
map $arg_type $image_type {
~^(?P<img_type>[0-9]{1,3}[a-z]{0,4})$ $img_type;
}
location ~ "^/resize.php$" {
try_files /images/${image_dir}/${image_name}.jpg /imagenes/elements/thumbs/${image_type}_${image_name}.jpg #phpresize;
}
location #phpresize {
# No changes from your config here.
try_files $uri =404;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
proxy_pass http://www.localhost.com:8080;
}

Related

Nginx - Rewrite rule under proxy failed

I have some issues with a "basic" rewriting rule under a proxy_pass location type :
location ~* /test1/network/v1/operator/ke3/dataUp {
rewrite ^(?<begin>/test1/network/v1/operator/ke3/dataUp)(?<parametersPart>.*)(?<mustDie>/dataUp)$ $parametersPart break;
proxy_pass http://server_preproduction;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
}
I expect any calls sent to : .../test1/network/v1/operator/ke3/dataUp?param1=GHJ&param2=865/dataUp
To be equal to : .../test1/network/v1/operator/ke3/dataUp?param1=GHJ&param2=865
So I just want to parse the parameters section in order to remove any extra /dataUp from the original request.
But when I try to use any kind of regex to do so, nginx seems to return to the location / and use the default request...
I'm sure that the proper location is use, becanse when I use a rewrite like : rewrite ^(?<begin>/test1/network/v1/operator/ke3/dataUp)(?<parametersPart>.*)$ TEST$parametersPart break;
The log on the proxy server received : TEST?param1=GHJ&param2=865/dataUp
I do not add a / at the end of the proxy_pass because I want replace all the url.(but it's not mandatory ! I tried lot of combinations...)
If someone can save my day :p
Thanks !!
I find a way to manipulate the argument with a simple if statement...
if ($query_string ~ "^(?<argsok>/dataUp.*)(?<argsko>/dataUp)$") {
proxy_pass http://server_preproduction/$argsok;
}

how to set the locaction in nginx.conf for removing URL's trailing slash?

Today I used two servers for nginx, the content of nginx.conf as follows:
#192.168.2.98
server {
listen 8091;
location ^~ /ttank {
alias /develop/servers-running/front/vue-public/dist;
index index.html;
try_files $uri $uri/ /ttank/index.html;
}
}
#192.168.2.97
location /ttank {
proxy_pass http://192.168.2.98:8091;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
I can access the 192.168.2.98:8091/ttank by enter address: http://192.168.2.98:8091/ttank in chrome, I also can access 192.168.2.98's ttank by entering the address http://192.168.2.97/ttank/, but when I change the addres http://192.168.2.97/ttank/ into http://192.168.2.97/ttank, my chrome entered into waiting status forever, the only difference between two addresses is the last "/", I don't know how to modify the config file for removing the last "/" when accessing ttank by 192.168.2.97?
Try usinge a rewrite rule to get rid of the ending slashes
location /ttank {
rewrite ^/(.*)/$ /$1 break;
...;
...;
proxy_pass ...;
}
it should do it

nginx location with and without trailing slash

I would like to create a location which catches both http://example.com and http://example.com/ and another location which catches everything else. The first one will serve static html and the other one is for the api and other stuff. I've tried with this:
location ~ /?$ {
root /var/www/prod/client/www;
}
location ~ /.+ {
# https://stackoverflow.com/questions/21662940/nginx-proxy-pass-cannot-have-uri-part-in-location
rewrite ^/(.*) /$1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 1s;
proxy_send_timeout 30s;
proxy_read_timeout 300s;
send_timeout 300s;
proxy_redirect off;
proxy_pass http://backendPro;
}
But does not work. I've tried with many options in first location, but when it matches first then second is not matching and vice-versa:
location / {
location ~ \/?$ {
location ~ ^/?$ {
It is actually much simpler:
location = / {
# Exact domain match, with or without slash
}
location / {
# Everything except exact domain match
}
Because location = / is more specific, it is always preferred if only the domain name is called (order of the location blocks does not matter).
You need regex in Nginx much less than you would think, because normal location blocks match every URL that matches the beginning, so location /bla matches every URL on the domain which starts with /bla (like /blabla, or /bla/blu, or /bla.jpg). I would mainly recommend regex if you need capturing groups and do something with those.

How to configure Nginx to try two upstreams before 404ing?

Given an Nginx configuration roughly like this:
upstream A {
server aa:8080;
}
upstream B {
server bb:8080;
}
server {
listen 80;
location #backendA {
proxy_pass http://A/;
}
location #backendB {
proxy_pass http://B/;
}
location / {
# This doesn't work. :)
try_files #backendA #backendB =404;
}
}
Basically, I would like Nginx to try upstream A, and if A returns a 404, then try upstream B instead, and failing that, return a 404 to the client. try_files does this for filesystem locations, then can fall back to a named location, but it doesn't work for multiple named locations. Is there something that will work?
Background: I have a Django web application (upstream A) and an Apache/Wordpress instance (upstream B) that I would like to coexist in the same URL namespace for simpler Wordpress URLs: mysite.com/hello-world/ instead of mysite.com/blog/hello-world/.
I could duplicate my Django URLs in the Nginx locations and use wordpress as a catch-all:
location /something-django-handles/ {
proxy_pass http://A/;
}
location /something-else-django-handles/ {
proxy_pass http://A/;
}
location / {
proxy_pass http://B/;
}
But this violates the DRY principle, so I'd like to avoid it if possible. :) Is there a solution?
After further googling, I came upon this solution:
location / {
# Send 404s to B
error_page 404 = #backendB;
proxy_intercept_errors on;
log_not_found off;
# Try the proxy like normal
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://A;
}
location #backendB {
# If A didn't work, let's try B.
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://B;
# Any 404s here are handled normally.
}

nginx location matching for url params only

I need to rewrite any root subdomain requests and append locale params if they aren't already there. e.g. -> de.example.com needs to be rewritten as -> de.example.com/?locale=de. then I proxy it off to the app.
2 questions:
1) is this the correct approach? or should I be using regex instead here? (new to this
so if other problems, please lmk)
2) is there a way to log things inside the location block? Having trouble getting same config working on another server, logging would help. (e.g logging what args is if it isn't matching, or if it matches on another location block).
It only needs to happen on the root page so this is my current config
#existing default (nonsubdomain block)
server {
server_name _;
root /var/www/web_app;
try_files $uri/index.html $uri.html $uri #app;
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
#just added for subdomain
server {
server_name de.example.com;
root /var/www/web_app;
location / {
try_files $uri/index.html $uri.html $uri #app;
}
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
location = / {
if ($args != locale=de ){
rewrite ^ $scheme://de.example.com/?locale=de permanent;
}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
1) is this the correct approach? or should I be using regex instead here? (new to this so if other problems, please lmk)
You should use $arg_locale != de instead of $args != locale=de. Look at the docs: http://nginx.org/en/docs/http/ngx_http_core_module.html#var_arg_
2) is there a way to log things inside the location block? Having trouble getting same config working on another server, logging would help. (e.g logging what args is if it isn't matching, or if it matches on another location block). It only needs to happen on the root page so this is my current config
Debug log: http://nginx.org/en/docs/debugging_log.html

Resources