What's the best way to rewrite a single character in NGINX? - regex

I had a bunch of urls like so:
http://domain.com/l/key-a=value-a/key-b=value-b.html
They were indexed by Google, but have since changed in our system from = signs to - signs, so I would like to redirect request like the one above to:
http://domain.com/l/key-a-value-a/key-b-value-b.html
Note: there could be one or more key-value param sets, the above is just an example.
What's the best way to do this in NGINX?

I was able to solve this using the following block:
location ~ /l/(.*)=(.*) {
rewrite ^([^=]*)=(.*)$ $scheme://$host$1-$2;
return 301;
}
This seemed to work even when there are multiple key-value pair segments in the the path, ex:
domain.com/l/color=red/size=large/shape=round
UPDATE:
I discovered that in cases where multiple key-value segments were present, there were multiple 301 redirects, and Google doesn't like this.
So I ended up going with:
location ~ /l/(.*)=(.*) {
rewrite ^([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4-$5-$6-$7-$8-$9 permanent;
rewrite ^([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4-$5-$6-$7-$8 permanent;
rewrite ^([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4-$5-$6-$7 permanent;
rewrite ^([^=]*)=([^=]*)=([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4-$5-$6 permanent;
rewrite ^([^=]*)=([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4-$5 permanent;
rewrite ^([^=]*)=([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3-$4 permanent;
rewrite ^([^=]*)=([^=]*)=(.*)$ $scheme://$host$1-$2-$3 permanent;
rewrite ^([^=]*)=(.*)$ $scheme://$host$1-$2 permanent;
}
The decreasing powers of 2s example (How to replace underscore to dash with Nginx) did not work for me.

Related

regex nginx remove trailing slashes not apply to 2 folders?

We want nginx to permanent redirect url's with a trailing slash to the non slash url. we found:
https://www.scalescale.com/tips/nginx/nginx-remove-trailing-slash/
So we put:
rewrite ^/(.*)/$ /$ permanent;
In the nginx, but the problem is it must not apply to some folders. so we found:
remove trailing slash in nginx with some certain cases ignored
and we changed it to:
rewrite ^/(?!admin)(.*)/$ /$ permanent;
but then the server wouldn't start:
invalid number of arguments in "rewrite" directive in /opt/www/folder/.nginx:5
And: we want 2 folders excluded.
What is the right regex to exclude the folders from the rewrite rule?
Thanks,
Bart
Edit for who comes here by google:
The answer works... only strange thing is that the standard worked without the $1 :
rewrite ^/(.*)/$ /$ permanent;
and now we made the exclude, it didn't work anymore without the $1.... but this works for now:
# remove trailing slashes
rewrite ^/(?!folder1|folder2)(.*)/$ /$1 permanent;
I suspect this is just a typo. That /$ looks like it should be /$1:
rewrite ^/(?!admin)(.*)/$ /$1 permanent;
If you have more that one URI to exclude, try something like
rewrite ^/(?!admin|secure|raw)(.*)/$ /$1 permanent;
nginx uses the same regular expression library as Perl, so you can test this stuff from a command line with
perl -ple 's#^/(?!admin|secure|raw)(.*)/$#/$1#'
and just typing in example URIs.

Rewrite with 404 urls with nginx

I'm trying to rewrite some urls which are showing up as 404's but the I can't get the rewrite to work. The Urls look like this /ossobuco-alla-milanese​​/1451114854360.1451114854360?time=1451114851111. I would like to remove 1451114854360.1451114854360?time=1451114851111 with a rewrite.
In my nginx config I have the following rewrite rule
rewrite "^\/(.*)\/(\d{13}\.\d{13}\?time=\d{13})$" /$1/ permanent;
I tested the regex in 2 online regex tools regex101 and regex pal and it should work but the don't seem to work on my server.
To match query string use $args:
location / {
if ($args ~* "^time=\d+") {
set $args '';
rewrite "^/(.+)/\d+\.\d+/?$" /$1 permanent;
}
}
PS: If you want to match only 13digits.13digits then use:
rewrite "^/(.+)/\d{13}\.\d{13}/?$" /$1 permanent;
In the end its was just a really simple location block and the ? removes the args.
location ~* ^/(.+)/\d+\.\d+$ {
rewrite ^/(.+)/\d+\.\d+$ /$1? permanent;
}

nginx redirect ignoring slash

I have some URLs that looks like this:
http://www.mywebsite.com/stuff/web-design-development
http://www.mywebsite.com/web-design/
http://www.mywebsite.com/web-design/secondary-page
Basically, I need anything from /web-design, with or without slash, and including anything after a slash (like the third URL) redirected to /. But the problem I'm having is that my redirect affects the first URL, because it has "web-design" in it.
Here's what I have:
if ($request_filename ~ web-design/.+) {
rewrite ^(.*) http://www.mywebsite.com permanent;
}
Any idea how I can correct this?
A simple location block will match all these
location /web-design {
return 301 $scheme://www.mywebsite.com;
end
This will match any thing that starts with /web-design and redirect it.
Here's why return and not rewrite and here's the location directive documentation.
Also keep in mind that 301 responses are cachable, if you are experiencing weird behaviour consider clearing your cache because maybe your browser cached an old 301 when the configuration wasn't correct yet.
I was able to solve this by simplifing my rewrites.
Instead of using if statements, I just did:
rewrite ^/web-design/?$ http://www.mywebsite.com/ permanent;

Combine three nginx rewrites into one

Is it possible to rewrite this regular expression so it fits all my use-cases below?
location ~ \.mp3$ {
rewrite "^/(\d{4})/0(\d)/0(\d)/(.*).mp3$" /$1/$2/$3/$4.mp3 permanent;
rewrite "^/(\d{4})/0(\d)/(\d{1,2})/(.*).mp3$" /$1/$2/$3/$4.mp3 permanent;
rewrite "^/(\d{4})/(\d{1,2})/0(\d)/(.*).mp3$" /$1/$2/$3/$4.mp3 permanent;
}
Real URL: 2012/7/8/piper.mp3
Should match:
2012/7/8/piper.mp3
2012/07/8/piper.mp3
2012/7/08/piper.mp3
2012/07/08/piper.mp3
Thanks

nginx Rewrite Rules to Re-write Every Match Of a Certain Regex Except

I'm writing rewrite rules in nginx.
I want to rewrite every URI that matches /A/B[anything] to /X/ except /A/B/C[/].
How do I do this?
What I've tried:
if ($request_uri ~ ^/A/B/C/?) {
break;
}
rewrite ^/A/B /X/ permanent;
This rewrites /A/B to /X/, but /A/B[anything] doesn't get redirected, nor does /A/B/C/ stay at /A/B/C/.
rewrite ^/A/B/?$ /X/ permanent;
Should do it
I figured out the issue.
I needed to make the rewrite line
rewrite ^/A/B(.*)? /X/ permanent;
The (.*)? means " and optionally match anything any amount of times."