how to do nginx rewrites from a url with get parameters - redirect

This is my first ever StackOverflow question so please bear with me.
Nginx serves many different sites for us and we have a lot of redirects from migrating clients from different vendors and such. We have set up an /includes directory that houses redirect files for each domain that we migrate over. Occasionally, we will need to write redirects from a url that contains get parameters:
http://example.com/content/default.aspx?NewsId=28
To do this, we have been doing this in an nginx /includes file called example.com-redirects
location ^~ /content/default.aspx {
if ($args ~ "NewsId=28") { rewrite ^ http://example.com/news? permanent; break; }
# add more statements like the one above
}
That has worked just fine for us thus far. Unfortunately, we need to do the same thing but for a different domain that could have the same get parameters. And of course nginx doesn't allow for duplicate locations.
location ^~ /content/default.aspx {
if ($args ~ "NewsId=28") { rewrite ^ http://differentexample.org/news? permanent; break; }
}
I've tried a couple of different solutions all giving me syntax errors. No one at my company is an nginx expert anymore so I could really use some help solving this. I have added an if ($host ~ "example.com") within the location block and that gave me an error. And I've tried adding the location block within the if ($host ~ "example.com") block. Both times nginx told me that I can't put that there.
I usually find my answer in the vast knowledge base that is the internet but seem to be striking out on a solution for this and we're running out of time before we launch this client.

Instead of using if, use a variable. In the virtual host config you set this variable. In the include with the location you use it:
server {
...
set $redirect_host "example.org";
include /includes/news28.conf;
...
}
# include part
location /foo {
if ($args ~ "NewsId=28") { rewrite $scheme://$redirect_host/news? permanent; }
}
Of course you need to set that variable also in the server config of the host already using this include. Hope this helps.

Related

Nginx: one directory should be redirected below itself

I have been struggling with a simple problem with nginx redirecting, but to avail so far.
I have two (language based) domains:
server {
server_name a.b.com;
.
.
.
}
server {
server_name d.b.com;
.
.
.
}
Now on d.b.com/example, should redirect to d.b.com/example/right. I have tried to build a location like below (plus a lot of variations of it including full urls).
location ^/example {
redirect /example /example/right permanent;
}
Nginx allows the syntax, but when I try to open the page, I always get the 404.
I think this should be straight-forward but my brain just can't get it right, nor have I found the solution in the web.
The biggest problem is that the end users already sent the mass mailing to our customers with the invalid link (without even checking it!), so I am a bit hard pressed with timetable...
wbr
hank
If you are trying to match a single URI, use an exact match location:
location = /example {
return 301 /example/right;
}
See this document for details.

Permanent redirect from example.com/ to https://www.example.com/dir/

I have some software build with microservice philosophy. On of them - which was hosted on example.com/ became useless so I want the user to be redirected to example.com/dir/ where another service is hosted. The most popular solution on StackOverflow is to use the following code in the configuration file:
location = / {
return 301 $scheme://$http_host/dir/;
}
or
location = / {
return 301 https://$http_host/dir/;
}
They both fail on my server - the server returns 503 - to many computations. The stacktrace shows, that there is no rule-infinite-rule so this code might be returned by load-balancer.
Is there any other well working solution for this issue? StackOverflow and ServerFault have just been carefully searched for the last 3 days by me and any solution worked.
After researching together with my teammates it has occured, that not only return 301 url; succesfuly redirects user. Although the documentation says avoid using rewrite what has worked is:
server {
...
rewrite ^/$ https://$http_host/dir/ permantent;
...
}
The permantent statement is responsible for acting as a regular redirection.
Important:
In nginx ^ is the begining of a regular expression and of the incomming string and $ sign is a normal regex sign which stands for theEndOfString. So regex ^/$ means match iff url equals /.
Credits:
Hopefully this will save one's weekend-time and money.
The = sign is invalid.
location / {
return 301 https://$http_host/dir/;
}
But that will end in a redirect loop, so be more specific:
location ~ ^[/]?$ {
return 301 https://$http_host/dir/;
}

nginx 301 redirect with query_string variable and if

I'm new to nginx and I need to setup up a load of 301 redirects each pointing old files to the new ones, like this:
# www.domain.com/products/category/product.php?id=103
# to
# www.domain.com/products/new-category-name/new-product-name.html
To deal with the ? I have the following which seems to be working fine:
if ($args ~ "id=103") {
rewrite ^ /products/new-category-name/new-product-name.html? permanent;
}
How does this look? I'm aware that if is mostly a bad idea in nginx but I don't fully understand why. Is the above rule okay? it seems to work fine. Lastly, I have around 100 of these urls to redirect. Will it be okay to just duplicate this rule for each url?
Thanks
UPDATE
The mapping looks to be a great solution but I'm not sure where to place the code. I currently have the following:
location / {
try_files $uri $uri/ #modx-rewrite;
}
It's stated that any additional rules need to be placed before this location block.
I would sugguest to use the ngx_http_map_module
create a file for the urlmapping, that contains old and new urls, like
/products/category/product.php?id=103 /products/new-category-name/new-product-name.html ;
/products/category2/product.php?id=104 /products/new-category2-name/new-product104-name.html ;
that's easy to maintain. just add a new line for a new mapping and reload your nginx config.
in your nginx config create a location with a mapping like
map $request_uri $newuri {
include /path/to/your/mappingfile;
}
server {
...
location / {
if ($newuri) {
return 301 $newuri;
}
}
}

Nginx rewrite subfolder to subfolder

I have been having issues redirecting an old subfolder entirely to a new subfolder. I need to have both /old and /old/ go to /new and /new/ respectively
I also need to have any parameters followed after /old/blah/blah2/ to /new/blah/blah2/ so just basically replacing old with new no matter whats called. The below is the closest I can get.
location /account/ {
rewrite ^/account/(.*)$ https://$server_name/portal/$1 permanent;
}
Example of an actual URL:
www.domain.com/account/index.php?loend=true&cmd=callback&module=8
needs to be
www.domain.com/portal/index.php?loend=true&cmd=callback&module=8
Thank you
Can you try rewrite ^/account/(.*)$ /portal/$1; ? No need to put it into location /account/ { ... } – Guillaume Filion Jul 24 at 19:00
Using just: rewrite ^/account/(.*)$ /portal/$1;
without specifying the location has resolved all issues
Its should work but you're missing $ sign in it.
Here is corrected a bit code
rewrite ^/account/(.*)$ https://$server_name/portal$1 redirect;
or
rewrite ^/account/(.*)$ https://$server_name/portal$1 last;
or
rewrite ^/account/(.*)$ https://$server_name/portal$1;
Than reload config of nginx
service nginx reload
here is source site.
https://www.digitalocean.com/community/questions/301-redirect-nginx
Since this seems more of a redirect than a rewrite, I would use return
location ^~ /account(.*) {
return 301 https://$server_name/portal$1$is_args$query_string;
}
The $is_args$query_string is to append any query string like you mentioned in one of the comments loend=true&cmd=callback&module=8 and also mind that if the $server_name is the same name of server_name you can replace it with $http_host and keep it dynamic.

Redirecting and rewriting in NGINX

I'm trying to create a simple "Hello World"-like API and for that I need a rule to redirect/rewrite the URL to my API.
Let's say my file is called index.php, so whenever I make a GET to index.php I get a list of items.
The first thing I want to do is to redirect the URL mydomain.com/index.php to mydomain.com/api.
And second, when mydomain.com/api is accessed, I'd like the server to trigger the index.php file without rewriting the URL.
My current code looks like this:
location /api {
rewrite ^ $scheme://$host/index.php permanent;
}
location /index.php{
return 302 www.mydomain.com/api;
}
but it's not working as expected. Why and how can I fix it?
You need two rules for what you're trying to achieve.
The first one, the one that will receive requests and "translate" them to your under-the-hood script, should look like this:
rewrite ^/api\?(.+)$ /index.php?$1 last;
As for the second one, the one that should redirect all your users to the "beautiful" URL:
rewrite ^/index.php\?(.*)$ /api?$1 permanent;
Note that this second rule should be outside any location block and before any of those, as you're willing to redirect the user before anything else.
Cheers
# you don't need a rewrite. Use location with the "=" or exact match
location = /api {
alias /path/to/root;
index index.php;
}
location /index.php {
return 302 www.mydomain.com/api;
}
Hope it helps
Here is the second version of my answer using one redirect and an alias:
location /api {
alias /path/to/root;
index index.php;
}
# replace index.php with api
location /index.php {
rewrite (index\.php)(.*)$ /api$2 permanent;
}
My first solution did not forwarded the args. Reading #alexandernst solution gave a better idea of the problem.