Clean URI/URL Nginx Rewrite for multiple pages & multiple variables - nginx

I am pretty much a moron with regex and I'm just getting started with a cloud-based Nginx server, which is a big change from administering my in-my-closet Apache server.
I'm trying to do rewrites to get clean URLs like this:
www.domain.com/folder/red/abc ---> www.domain.com/folder/red.cfm?query=abc
www.domain.com/folder/blue/ab/cd/ef ---> www.domain.com/folder/blue.cfm?name=ab&city=cd&state=ef
www.domain.com/folder/blue/ab ---> www.domain.com/folder/blue.cfm?name=ab
I'm basically trying to get rewrites of items after the "folder" subfolder to rewrite to static .cfm pages. Some of those .cfm pages have zero, one, two or three URL variables; the number of variables is not fixed or consistent.
I have been reading A LOT about rewrites and try_files, and I have tried, oh, a couple hundred different variations of rewrites, and I just can't seem to find the solution.
For example, I've tried:
location /folder/blue {
rewrite ^/folder/(.*)?$ /folder/blue.cfm?name=$1 last;
}
And this just gets me absolutely nowhere. I would post my entire conf file, but it is long due to other stuff that was added in by the default server setup.
I would love to make this string as simple as is humanly possible, but I really need help with this. I appreciate it!

For future reference, it would help having a spec.
It seems like this is the only spec you've provided:
www.domain.com/folder/red/abc ---> www.domain.com/folder/red.cfm?query=abc
www.domain.com/folder/blue/ab/cd/ef ---> www.domain.com/folder/blue.cfm?name=ab&city=cd&state=ef
www.domain.com/folder/blue/ab ---> www.domain.com/folder/blue.cfm?name=ab
The following solution should 100% satisfy the above "spec":
location /folder/red/ {
rewrite ^(/folder/\w+)/(\w*)$ $1.cfm?query=$2 last;
return 410;
}
location /folder/blue/ {
rewrite ^(/folder/\w+)/(\w*)$ $1.cfm?query=$2 last;
rewrite ^(/folder/blue)/(\w*)/(\w*)/(\w*)$ $1.cfm?query=$2&city=$3&state=$4 last;
return 410;
}

Related

Rewrite URL /blog/content/images/**/* to /content/images/**/*

My front-end is hitting /blog/content/foo/bar.jpg when looking for static assets.How can I make NGINX redirect those requests to /content/foo/bar.jpg instead?
At first I tried this:
location ~ ^/blog/content/ {
root /var/www/ghost/content/;
}
Apparently it didn't work – (btw, I'm testing each change in the .conf file with a sudo nginx -s reload + F5 in the browser.. is there a better way to test/debug NGINX behavior (and actually understand what's going on instead of this "worked / didn't work" feedback I get with each F5?)
Then, I tried this one I found in a cheatsheet – at the server level:
rewrite ^/blog/content/(.*)$ /$1 last;
Again, without luck. What bothers me is that I can't even see what the line above is doing and why it isn't working.
Someone, please, get me out of this "google for a solution -> try something that looks promising --> hit F5 hoping it works (it doesn't) -> google for a solution" loop.
The solution I found was to rewrite with:
rewrite ^/blog/(.*)$ /$1 last;
But it isn't ideal. I'd prefer to rewrite only when the URI contains "/blog/content/"..

Nginx rewrite '*/filename/playlist.m3u8' to '*/filename.mp4/index.m3u8' as redirect

I'm trying to migrate over from Wowza and set-up VOD on Nginx on Debian through the help of Kaltura's nginx-vod-module, everything is working fine, apart from the existing VOD archive still req. to be accessible through the old URLs... so a rewrite rule is in order, but since it's a bad practice to do this, it should be a nginx redirect 'return 301 '.
The previously used Wowza URL format for files in the VOD archive was:
http://<server-address>:<rtmp-port>/vod/<file-name>/playlist.m3u8
The new URL format has to be:
http://<server-address>/vod/<file-name><file-extension>/index.m3u8
While I don't know much about rewrite rules, for now I've managed to put together a temp solution:
location ~ playlist.m3u8$ {
rewrite ^(.*)/playlist.m3u8$ $1.mp4/index.m3u8;
}
But I don't know how would that translate into a working Redirect rule ('Return 301 ') or if it's possible to have one that would work universally without specifying each and every filename in the VOD folder.
While I'm at it, it kinda would be nice to have a simpler/shorter URL to access the newly added files.
http://<server-address>/vod/<file-name>.m3u8
The rewrite rule that should do that I think would be a combination of two rewrite rules, something like:
location ~ playlist.m3u8$ {
rewrite ^(.*)/playlist.m3u8$ $1.mp4/index.m3u8;
}
location ~ index.m3u8$ {
rewrite ^(.*).m3u8$ $1.mp4/index.m3u8;
}
But I'm worried it would target the URLs that have been rewritten and result in a HTTP error 404... suggestions to avoid that?
Try this:
rewrite ^http://(.*?):\d+/vod/(.*?)/.*?\.(.*)$ http://$1/vod/$2.mp4/index.$3
Regex101

Drop all GET Parameters from main index file in Nginx

I would like to remove all GET parameters from the index file in the root folder, while leaving all GET parameters everywhere else.
Example:
http://support.oursite.com/?ref=inline
I would like that to get ported to
http://support.oursite.com/
While
http://support.oursite.com/tickets/?id=1934
Would still contain the ID parameter.
I have been able to wipe the parameters, what I'm looking for is help on limiting that wipe to just the root index.
I've found the solution to this, for anyone who comes across this issue.
I have two separate location parameters:
location ~* ^/(.+)$ {
proxy_pass http://192.168.1.1/$1$is_args$args;
}
location / {
proxy_pass http://192.168.1.1/;
}
The use of the (.+) tells Nginx only run this location if there is something after the slash. Because GET parameters aren't processed in that spot, it's safe to do this.

conditional rewrite or try_files with NGINX?

I'm having trouble setting up a conditional rewrite, and I've been trying to use the if directive (despite all sources indicating it's "evil") with the -f switch to check for the presence of a file, but it's not working. I believe the issue/case is best explained by example, so here goes:
Directory structure
workspace/
myapp/
webroot/
index.php
assets/
baz.js
hello/
foo.js
modules/
hello/
assets/
foo.js
bar.js
Expected results
/ => /workspace/myapp/webroot/index.php
/assets/hello/foo.js => /workspace/myapp/webroot/assets/hello/foo.js
/assets/hello/bar.js => /workspace/myapp/modules/hello/assets/foo.js
/assets/baz.js => /workspace/myapp/webroot/assets/baz.js
In summary:
foo.js is only present in the modules/hello/assets folder and gets delivered from there.
bar.js is present both in webroot/assets/hello and modules/hello/assets and gets delivered from webroot.
(it hides/overrides the file in modules)
baz.js is only present in webroot/assets and gets delivered from there.
The part that doesn't work right now, is this:
location /assets/ {
if (-f $uri) {
break;
}
root /workspace/myapp/modules;
rewrite ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
}
Namely the if directive, doesn't seem to have any affect - the bar.js file gets delivered from modules rather than webroot.
Should I be using if or not?
Is there any way I can solve this problem with try_files instead? I can't seem to grasp how this would work together with rewrite which I can't seem to get around.
Please do not suggest reorganizing the assets using a deploy script or something - it's not an option, for various other reasons.
I have used this pattern with Apache before, and NGINX seems more capable in most respects, so I'm sure this must be possible?
One requirement that isn't absolute, is I don't have to be able to override modules/hello/assets/foo.js with webroot/assets/hello/foo.js - serving scripts from webroot/assets/* is however a requirement.
The answer is divided into two parts: the first part explains why your configuration does not work and the second one provides examples of how to solve your problem. If you are only interested in the solution, go straight to the second part.
The problem
First of all, note that the positon of the root directive in a location block is not important. It does not matter if you put it at the very top or at the bottom of a location, it will affect the whole location anyway. Also, keep in mind that break in the end of the rewrite line tells Nginx to stay within the current location even if the URI has been successfully rewrited.
Having said that, let's take a look at your configuration and see how every request from the Expected results is processed and why nothing works as expected.
Let's presume that there is no other suitable location with a higher priority in your configuration. Since every request from Expected results starts with /assets, all of them will be handled according to the rules presented in your location. So:
/assets/hello/foo.js
The root is set to /workspace/myapp/modules. The if directive will be evaluated to false, because /assets/hello/foo.js does not exist and so break will not be executed. Finally, the last rewrite will change the requested URI from /assets/hello/foo.js to /hello/assets/foo.js and the following break will tell Nginx to stay within the current location. As a consequence /workspace/myapp/modules/hello/assets/foo.js will be served.
/assets/hello/bar.js
This request is processed exactly the same way as the previous one, so /workspace/myapp/modules/hello/assets/bar.js will be served.
/assets/baz.js
Yet again the root is set to /workspace/myapp/modules and the if is evaluated to false. But this time the final rewrite will not change the URI, because the request does not match the regular expression. As a consequence Nginx will try to serve /workspace/myapp/modules/assets/baz.js and since there is no such file exists, will return 404.
As you can see your configuration cannot possibly work as you want it to for several reasons:
if is always evaluated to false, because you try to check URIs and not files;
the request stays within the location because you tell it to stay there with break in the rewrite line;
root is always set to /workspace/myapp/modules in this location so no file can be served from anywhere else.
The solutions
The easiest solution would be to use try_files:
root /workspace/myapp/webroot;
location /assets/ {
try_files $uri #modules;
}
location #modules {
root /workspace/myapp/modules;
rewrite ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
}
This configuration tells Nginx to look for a file in the webroot folder first and if nothing is found then go to the modules folder in another location. This approach is considered most preferable.
On the other hand, using if would allow you to solve the problem within one location:
location /assets/ {
root /workspace/myapp; # The parent folder
if (-f $document_root/webroot/$uri) {
rewrite ^(.*)$ /webroot/$1 break;
}
rewrite ^/assets/([^/]+)/(.*)$ /modules/$1/assets/$2 break;
}
However, this approach is considered outdated is not recommended for use.

How to make nginx to stop processing other rules and serve a specific location?

I have this config that works as expected in an empty server { } definition
location ^~ /foo/ {
alias /var/www/foo/;
}
But when I move this in a considerably bigger server definition (one used for a WordPress multi-site config), it will stop working and wordpress will respond to it (which obviously was not my intent).
I tried to put at the begining or end of server block, but this didn't change it.
How can I force Nginx to use this location?
You are probably looking for break.
location ^~ /foo/ {
alias /var/www/foo/;
break;
}
From the HttpRewriteModule documentation:
last - completes processing of current rewrite directives and
restarts the process (including rewriting) with a search for a match
on the URI from all available locations.
break - completes processing of current rewrite directives and
non-rewrite processing continues within the current location block
only.
Note that outside location blocks, last and break are effectively the
same.
Location blocks in Nginx are exclusive. If you use location ^~ then other rules probably expiry headers for static objects will not apply unless you copy those rules as nested under the same location block.
If you could share your full config then I can make it work for you. Most likely you need to use nested location blocks.
location = /aliasname/ {
alias /path/to/alias/
}
Trailing slash will be a problem if it is not present in URI.
See https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms#matching-location-blocks

Resources