Nginx how to pass a parameter to proxy server? - nginx

I have a very simple problem but I am new to nginx so I may be missing some obvious solution.
So I have a location defined in nginx
/example/$id
I would like to pass $id to parametrized route on my proxy server like so
http://server.com/example/$id
This gives me unknown id variable on nginx reload. So my question is how can I pass a parameter from nginx to my proxy server.

Assuming all the rest are correctly set, you can just create a location with a regex and pass the captured variable to your proxy.
location ~ ^/example/(.+)$ {
proxy_pass http://server.com/example/$1;
}
If your $id is numeric only, the regex could be more restrictive
location ~ ^/example/(\d+)$ {
proxy_pass http://server.com/example/$1;
}
Note that you can't just use a variable without declaring it first. Declaring $id is not necessary, it is captured inside the parentheses of the regex and passed to $1

Related

NGINX - different backend proxy based on query parameter

I've got a particular scenario where I'm needing to route to a different backend based on query parameter:
https://edge1.cdn.com/file.zip?{secure_link}&{tokens}&route=aws1
Where aws1 would be say http://edge1.amazonwebservices.com
and if its aws2 then proxy backend would be http://edge2.amazonwebservices.com
and so on... but I still have not figured out how to do this.
You can use map directive to get a proxy hostname from the $arg_route variable (which contains a value of the route query argument):
map $arg_route $aws {
aws1 edge1.amazonwebservices.com;
aws2 edge2.amazonwebservices.com;
...
default <default_hostname>;
}
server {
...
# if you want to proxy the request, you'd need a 'resolver' directive
resolver <some_working_DNS_server_address>;
location / {
# if you want to proxy the request
proxy_pass http://$aws;
# or if you want to redirect the request
rewrite ^ http://$aws$uri permanent;
}
}
If you don't want to serve the request without route query argument, you can omit the last default line at the map block and add the following if block to your server configuration:
if ($aws = '') {
return 403; # HTTP 403 denied
}
If you need to proxy the request you'd additionally need a resolver directive (you can read some technical details about it in this article).

How to get lua variables back into nginx variables

I have a lua script that uses lua-resty to call another service via co-sockets.
Now I would like to use the information from this call to route the request in nginx.
nginx includes the lua script in access_by_lua*
which sets the var like this:
ngx.var.blocked = '1'
and routes in the location like this:
if ( $blocked ) {
proxy_pass http://haproxy-9001;
break;
}
the problem is now that nginx does not pick up the variable change (in this phase).
if I include the lua script in set_by_lua* phase then the variable passing works but I dont have access to the co-sockets in this phase.
Any idea how to get the variable out of lua land into the nginx variable in the access_by_lua, rewrite_by_lua or content_by_lua phase so that I can use the co-socket api to make a http call?
if nginx directive is implemented by https://nginx.ru/en/docs/http/ngx_http_rewrite_module.html.
Obviously it works on rewrite phase, so your changes at access phase doesn't work.
Just don't use if. Below is snippet from one of my nginx config:
proxy_pass $scheme://$upstream$uri$is_args$args;
Just set $upstream variable at access phase and it will work at content phase (proxy_pass).
Maybe you could capture location with that proxy instead of variable, it works in access_by_lua scope
https://github.com/openresty/lua-nginx-module#ngxlocationcapture

Nginx: How to escape argument value for proxy_pass

We have such a location configuration:
location ~ ^/suggest/(?<search>.+) {
proxy_pass https://internal.host/v1/products?suggest=$search;
}
The problem is that internal.host receives $search as is, which means that anyone from the outside can pass &another_param=value as a value of $search and thus gain unauthorized access to the remote endpoint.
The question is: how to escape the argument value?
location ~ ^/app/(.*)$ {
proxy_pass http://192.169.154.102:9999/some_dir/$1;
}
This examples results in:
test.com/app/request/xxxxx => http://192.168.154.102:9999/some_dir/xxxxx
Not that the example needs to be adjusted to fit your needs.
Please review this link for more information on proxy_pass(ing) with arguments. Additionally your web application/script that takes in the arguments should perform a check on the parameters given. Before anything is done with the parameters, perform checks and/or filtering of the parameter passed! Please also do some checks, if the above method does limit the parameter, which it should - but please check.
Example from: Nginx proxy_pass: examples for how does nginx proxy_pass map the request.

how to use url pathname as upstream hash in nginx

I have a nginx server with config to use queryparam as upstream hash. Url looks like below
http://www.my-server.com/xyz/WXYZ?abc=123
And configuration as below
upstream test {
hash $arg_abc;
....
}
is there any possibility to use WXYZ part of URL as upstream hash?
WXYZ is dynamic value and xyz is always same and will be there.
this is what I tried,
location ~ ^/xyz/(.).*$ {
hash $1
}
The deployment guide explicitly said it's possible:
The generic hash method: the server to which a request is sent is
determined from a user-defined key which may be a text, variable, or
their combination. For example, the key may be a source IP and port,
or URI:
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
The hash key is $request_uri which can be replaced with $arg_your_key but not sure is works with upstream block, however it should work as proxy_pass value:
location /xyz {
proxy_pass http://localhost/$uri$is_args$args;
}
Not sure of requirements but if you need to use certain backend based on argument $arg_abc you need map function, like here:
map $arg_abc $backend_server {
default 'serverdefault.domain.com:80';
123 'server1.domain.com:80';
234 'server2.domain.com:80';
345 'server3.domain.com:80';
}
server {
location / {
proxy_pass http://$backend_server;
}
}
Yes, as per the documentation for hash, you can only use it in the upstream context, so what you've tried won't work indeed.
However, why exactly do you need to use only a certain path from your URI, instead of the whole thing, if those other parts stay the same anyways? I think the idea is that the whole string is supposed to be further hashed anyways, so, even if all your URLs start the same, the hash function is still supposed to distribute everything evenly. So, you can most likely just use $request_uri or $uri as your hash.
Alternatively, if you still want to do it your way, you might try to use named pattern matching in your location (location ~ ^/xyz/(?<varForHash>.).*$ {…), and then use the variables from such matches ($varForHash) as your hash (you could probably even use $1 from your example, too, just in the proper context — upstream).
I got similar task and I solved it.
I created upstream.conf and added it to the nginx.conf.
The upstream.conf content is below:
map $uri $myvar{
default $uri;
# pattern "Method1" + "/" + GUID + "/" + target parameter + "/" + HASH;
"~*/Method1/(.*)/(.*)/(.*)$" $2;
# pattern "Method2" + "/" + GUID + "/" + target parameter;
"~*/Method2/(.*)/(.*)$" $2;
}
upstream backend {
hash $myvar consistent;
server s1:80;
server s2:80;
}

how to avoid nginx to replace %20 by whitespace when using as a proxy (proxy_pass) ?

I am using a nginx as a proxy for an apache server.
Here is my config:
location ~ ^/subsite/(.*)$ {
proxy_pass http://127.0.0.1/subsite/$1?$query_string;
}
the problem is that if I send a request with %20 like mywebsite.com/subsite/variable/value/title/Access%20denied/another/example
the %20 is replaced by a whitespace, and apache don't care about all the end of the request after Access /title/Access
Any Idea ?
I was able to solve a similar issue -- we have an api that requires the search terms to be part of the URL path. Passing the output directly to the proxy_pass directive caused it to throw a 502 even though the request was properly url encoded.
Here's the solution we came up with:
location ~ /api/search(/.*) {
set $query $1;
proxy_pass http://127.0.0.1:3003$query;
}
The "set" directive seems to keep the url encoding intact (or re-encodes from what the regex is passing back in $1).

Resources