nginx 301 redirect with query_string variable and if - redirect

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;
}
}
}

Related

nginx: How to mass permanent redirect from a given list?

I have about 400 url that will change in the new version and for some reasons I can't repeat the same type of url structure in the new website.
My question is, can I give a url list to nginx (yeah I know the 400 ones), and tell him simply that each one of them are going to another url?
Like I said the url structure will be different so I can't use any type of pattern.
Thanks in advance.
The map directive
If you have a very long list of entries, it could be a good idea to keep them outside of the nginx configuration file - using a .map file.
First you need to add a map directive inside your nginx.conf file - keep in mind that your .conf file could be named in another way (e.g. default.conf).
nginx.conf
map_hash_bucket_size 256; # see http://nginx.org/en/docs/hash.html
map $request_uri $new_uri {
include /etc/nginx/oldnew.map; # or any file readable by nginx
}
server {
listen 80;
server_name your_server_name;
if ($new_uri) {
return 301 $new_uri;
}
...
}
Then, the map directive will map any $request_uri to the matching $new_uri found inside the oldnew.map file.
/etc/nginx/oldnew.map:
/my-old-url /my-new-url;
/old.html /new.html;
Be sure to end each line with a ";" char!
Additional configuration
If you need to redirect all URLs to another host, you can use:
return 301 http://example.org$new_uri;
Or, if you also need to redirect to another port, you can use:
return 301 http://example.org:8080$new_uri;
Probably the easiest way to do that is to wrap map directive around your list. The configuration in this case would look like this:
map $request_uri $new_uri {
default "";
/old/page1.html /new/page1.html;
/old/page2.html /new/page2.html;
...
}
server {
...
if ($new_uri != "") {
rewrite ^(.*)$ $new_uri permanent;
}
...
}

how to do nginx rewrites from a url with get parameters

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.

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.

How to set up nested subfolder to subdomain Nginx 301 redirects

I'm trying to set up Nginx redirects that will rewrite any URL from several older forum setups to a new forum. The older forums ran from subfolders, while the current forum is running from a subdomain of the same site.
So, for example, I want ANY request to site.com/ask to be redirected to the front page of forum.site.com. Since I'm dealing with 3 old forums, I tried to set up a nested redirect like this:
location ~ ^/\~([^/]+)/(.*)$ {
location ~ ^/\~ask/(.*)$ {
rewrite ^(.*)$ http://forum.site.com$1 permanent;
}
location ~ ^/\~forum/(.*)$ {
rewrite ^(.*)$ http://forum.site.com$1 permanent;
}
location ~ ^/\~qa/(.*)$ {
rewrite ^(.*)$ http://forum.site.com$1 permanent;
}
}
With the above rules, only the first one works and partially. For example, a request to site.com/ask gets redirected to forum.site.com, which is fine, but any request to, say, site.com/ask/what-is-this goes to forum.site.com/404.
Request to site.com/forum and site.com/qa do not work at all.
I'm sure there's a simpler way of doing this, but I don't want to spend several days trying to figure it out.
Your input is welcome and appreciated.
Edit:
Not getting anywhere with the above code, I reduced it to this:
location ~ ^/\~([^/]+)/(.*)$ {
location ~ ^/\~(qa|forum|ask)/(.*)$ {
rewrite ^/~(qa|forum|ask)/(.*)$ http://forum.site.com$1 permanent;
}
}
But the result is still the same. Any ideas?
Actually you want to redirect user to the main page of your forum regardless of what page he came to. Try this.
location /qa/ {
return 301 http://forum.site.com;
}
location /ask/ {
return 301 http://forum.site.com;
}
location /forum/ {
return 301 http://forum.site.com;
}