nginx location regex matches directory range
I am trying to set up nginx and I don't get the point how to do the following setup:
I have an URL http://somehost.com/foo/bar/123/xxx_xxx that needs to be passed to different backends depending on a range the '123' matches (e.g. 0-150 -> backend1, 151-400 -> backend2, ...).
Since I have almost no experience with regexp, I don't know how to do this (in location?).
Thanks in advance for your help, Sascha
Solution 1:
You can use:
location ~ ^/foo/bar/(\d|\d\d|1[0-4]\d|150)/ {
proxy_pass backend1;
}
location ~ ^/foo/bar/(15[1-9]|1[6-9]\d|[23]\d\d|400)/ {
proxy_pass backend2;
}
...
But why you do load balancing in such a heterogeneous way? Why not just shard by image id/hash of name? Your solution will result in different load and even load patterns on different servers. It would be tricky to administer them.
Solution 2:
If you have a static set of the picture sizes, you can make use of map
. Declare backends and a map in http
section of Nginx configuration file:
http {
upstream backend1 {
server backend1:80;
}
upstream backend2 {
server backend2:80;
}
map $pic_size $backend {
default backend_default;
80 backend1;
150 backend2;
}
}
Declare the location in server
:
location ~ ^/foo/bar/(?<pic_size>\d+) {
proxy_pass http://$backend;
}
If you'd like to support conditional logic, I would recommend using Perl handler. Again, in http
:
http {
perl_set $backend 'sub {
my $r = shift;
my $pic_size = $r->variable("pic_size");
$pic_size <= 150 and return "backend1";
$pic_size <= 400 and return "backend2";
return "backend_default";
}';
}
In location:
location ~ ^/foo/bar/(?<pic_size>\d+) {
proxy_pass http://$backend:80;
}