How to do nginx rewrite on a specific query string pattern? - nginx

We are getting lots of traffic to our main site in following patterns. The parameters is different everything this is messing up my cache. I need to do redirect:
These redirect to /?lang=zh-hans
/?lang=zh-hans&category=26%2C27&full=1&mo=9&yr=2022&id=1800312749
/?lang=zh-hans&category=26%2C27&full=1&mo=8&yr=2022&id=111871000
/?lang=zh-hans&id=1930613962&category=26%2C27&full=1&mo=10&yr=2022
/?lang=zh-hans&category=26%2C27&full=1&mo=08&yr=2022&id=1205387849
These redirect to /?lang=zh-hant
/?lang=zh-hant&category=26%2C27&full=1&mo=9&yr=2022&id=1800312749
/?lang=zh-hant&category=26%2C27&full=1&mo=8&yr=2022&id=111871000
/?lang=zh-hant&id=1930613962&category=26%2C27&full=1&mo=10&yr=2022
/?lang=zh-hant&category=26%2C27&full=1&mo=08&yr=2022&id=1205387849
To avoid the complexity, I just need to do it on the root path.
This is what I have tried on nginx, but it's not working.
rewrite ^/?lang=zh-hans&category=.+ /?lang=zh-hans permanent;

If I understand you correctly, you need to redirect all requests with parameters starting with /?lang=zh-hant… to the /?lang=zh-hant, and requests with parameters starting with /?lang=zh-hans… to the /?lang=zh-hans, omitting other GET parameters. This can be done somehow like this:
http {
… skipped …
map $request_uri $redirect {
"~^\/\?lang=zh-hans&.*$" /?lang=zh-hans;
"~^\/\?lang=zh-hant&.*$" /?lang=zh-hant;
}
server {
if ($redirect) {
return 301 $redirect;
}
… skipped …
}
}
Here, in map section we tell nginx to check if $request_uri is starting with ?lang=zh-hans& or ?lang=zh-hant& substring and set corresponding value to the $redirect variable.
Then in server section we tell nginx to check if $redirect exists and if so, return 301 redirect with location from that variable.
Please note, that tis will work only if lang parameter is the first in $request_uri, i.e. request to
/?lang=zh-hant&category=26%2C27&full=1 will be redirected, but
/?category=26%2C27&lang=zh-hant&full=1 will be processed without redirect

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).

Redirect whatever.net to whatever.com without explicitly writing "whatever" in nginx.conf

I have a web app, that will be running on many different domains (and possibly subdomains). Each domain/subdomain will be available as both .net and .com. I want to redirect every request of .net to .com.
Example:
www.whatever.net -> www.whatever.com
www.sub.whatever.net -> www.sub.whatever.com
whatever.net -> whatever.com
sub.whatever.net -> sub.whatever.com
somethingelse.net -> somethingelse.com
...
For various reasons I'd like to have only one nginx.conf file that works for every installation, so I can't write something like:
server {
server_name .net;
return 301 $scheme://whatever.com$request_uri;
}
Because this works just for the installation that's under the whatever.net/whatever.com domains. So I tried:
server {
server_name "~^(?<name>.+)\.net$";
return 301 $scheme://$name.com$request_uri;
}
But this does not work, it capture every request, not only those coming from the .net domain, and (on chrome at least) the result is that the content of the address bar become: .com/thequerypart.
I'm new to nginx, what am I doing wrong?
EDIT:
The rest of nginx.conf is another server block that starts with:
server {
server_name .com;
...
}
It works as intended without the other one.
I... didn't know browsers cache things that are "Moved permanently" (makes sense), the setup I've shown in the question worked, but a previous different attempt did not, and got cached. So, for anyone that may get here in the future, the answer is:
server {
server_name "~^(?<name>.+)\.net$";
return 301 $scheme://$name.com$request_uri;
}

Avoid redirect cycle when combining access_by_lua with ngx.exec to a (named) location

I want to change an existing nginx configuration in a way where I can completely "mask" the configuration and proxy everything to the upstream when a certain cookie is available (to hide a certain server).
This includes not just some location directives but basically every location directive (as opposed to set or map a variable and update n-location's try_files and more).
My basic idea was to use lua and jump into the Rewrite/Access phase like this:
access_by_lua_block {
# proceed as usual if our cookie is not detected
if ngx.var.cookie_demo ~= nil and string.len(ngx.var.cookie_demo) ~= 32 then
return
end
# proxy and return w/out further processing
ngx.exec("#ngxbackend")
return ngx.exit(ngx.HTTP_OK)
}
# proxy upstream
location #ngxbackend {
include /etc/nginx/proxy_params_demo;
proxy_pass https://demo-upstreams;
}
But this leads to an ERR with rewrite or internal redirection cycle while redirect to named location "#ngxbackend" as the named location is probably never reached because of the access_by_lua_block after it's internal redirect.
Can I solve this by use of variables and further condition checking?

Proxy a request - get a parameter from URL, add a header and update request URL using Nginx

I am looking for a way to do the following using Nginx:
Intercept a request
Read URL, parse it and read a value from it.
Add that value as a new request header
Update the URL (remove a particular value)
Forward the request to another server
e.g
Request URL - http://<<nginx>>/test/001.xml/25
Final URL - http://<<server>>/test/001.xml with header (x-replica: 25)
I have a nginx server setup with a upstream for the actual server. I was wondering how do I setup Nginx to achieve this ?
Since the data exists within the request URI itself (available by the $uri variable in nginx), you can parse that using the nginx lua module. nginx will need to be compiled with lua for this to work, see: openresty's nginx lua module.
From there you can use the set_by_lua_block or set_by_lua_file directive given $uri as a parameter.
In configuration this would look something like:
location / {
...
set_by_lua_file $var_to_set /path/to/script.lua $uri;
# $var_to_set would contain the result of the script from this point
proxy_set_header X-Replica $var_to_set;
...
}
In script.lua we can access the $uri variable from in the ngx.arg list (see these docs):
function parse_uri( uri )
parsed_uri = uri
-- Parse logic here
return parsed_uri
end
return parse_uri( ngx.arg[1] )
Similarly, you can modify this function or create another to make a variable with the updated $uri.

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