Basic nginx URL rewriting issue - nginx

I'm completely new to nginx and I was wondering if someone could give me a hand.
What I'm trying to to is turn this:
domain.com/ngu/short.php?t=123
into
domain.com/t/123
If someone could explain to me how it's done, I would be very grateful. I have looked around the site for a similar situation, but I haven't found anything exactly the same so I'm having some difficulty. Thank you for your time :).

the following location block does the rewrite:
location ~ /ngu/short.php {
if ($args_t) {
rewrite ^ http://$host/t/$v? last;
}
}
but that requires you enumerate all possible arguments, if you have lots of potential arguments it's probably easier to do
location ~ /ngu/short.php {
if ($args ~ "([a-z]+)=(\d+)") {
set $p $1;
set $v $2;
rewrite ^ http://$host/$p/$v? last;
}
}
explanation:
we do a location that matches on the /ngu/short.php path
the first code block above checks if we have a t=value argument and if so does the rewrite
the second code block above checks for a more general argument=something. We then need to save the backreferences in variables because a rewrite rule resets the backreferences which prevents using them directly
in either case if the if fails to match a 404 will be returned
$host and $args en $args_ are standard nginx variables see http://wiki.nginx.org/HttpCoreModule#Variables
we add a ? ad the end of the rewrite to keep nginx from readding the url arguments

In case this helps anyone else, this is what I (actually a friend) ended up doing:
location / {
root /home/jim/www;
index index.html index.htm index.php;
if (!-f $request_filename) {
rewrite ^/t/(.+)$ /ngu/short.php?t=$1 last;
rewrite ^/u/(.+)$ /ngu/short.php?u=$1 last;
rewrite ^/s/ /ngu/short.php last;
break;
}
}
I don't understand it, but it works.

Related

how to create an nginx rewrite to add / to url

I'm trying to create an nginx rewrite that will rewrite /pagename to /pagename/
I've tried using:
location ~ "^/test$" {
rewrite /test /test/ break;
}
but that doesn't seem to work...
any help would be appreciated.
The first parameter of a rewrite statement is a regular expression, and the flag you should use is probably permanent (see this document for details), for example:
location ~ "^/test$" {
rewrite ^(/test)$ $1/ permanent;
}
But you do not need to match the regular expression twice, once in the location and again in the rewrite, so a return would be more efficient, for example:
location ~ "^(/test)$" {
return 301 $1/$is_args$args;
}
Also, the location matches a single URI, to the = operator would be better than a regular expression (see this document for details). So the preferred solution is:
location = /test {
return 301 $uri/$is_args$args;
}
I ended up using return:
return 301 /test/;

nginx server: how to remove first directory from URL

Can anybody please help me to remove first directory name from URL?
My Image location is _data/hotel/3/15377/hotel_image.jpg
But Image path gets changed due to relative URL in code and it become to something like this.
example.com/france/_data/hotel/3/15377/hotel_image.jpg
example.com/usa/_data/hotel/3/15377/hotel_image.jpg
example.com/india/_data/hotel/3/15377/hotel_image.jpg
is their any possibilities to remove dynamic country name from above URL
If you want to rewrite only this particular URL, you can use this location block in your config:
location ~ /[a-z]+/_data/hotel/3/15377/hotel_image.jpg {
try_files /_data/hotel/3/15377/hotel_image.jpg;
}
If you want to rewrite all URLs which lead to /<country>/_data/..., you can use:
location ~ /[a-z]+/_data/(.+) {
try_files /_data/$1;
}
or for stricter URL checking:
location ~ /(?:france|usa|india)/_data/(.+) {
try_files /_data/$1;
}
#Ivan Shatsky's answer is great for files but also if we want to redirect a general url is better if you use the rewrite directive.
Depending where you define the rewrite directive you have two ways to implement it:
A. In the server context
server {
...
rewrite ^/[a-z]+/_data/(.+)$ /_data/$1 last;
...
}
B. In the location context
location ~ /[a-z]+/_data/(.+) {
rewrite ^/[a-z]+/_data/(.+)$ /_data/$1 break;
proxy_pass http://backend;
}
Teo, why did you change the flag to break?* Because, if this directive is put inside of a location context, the last flag might make nginx to run 10 cycles and return the 500 error.
Note:
Remember not add / at the end of the proxy_pass directive. This example wont work:
...
proxy_pass http://backend/;
...

If Is Evil - Nginx

I'm using Nginx 1.6.2. I read that if () is evil and it's not good using it so I need a bit help, because I can't do what I want without using if(). I will post the rules I have with if and would ask if somebody could help me and tell me how to not use if () and use something else and get the same result.
# REDIRECT NON-WWW TO WWW.
if ($http_host != "www.site.eu") {
rewrite ^ http://www.site.eu$request_uri permanent;
}
# REMOVE INDEX FILES FROM URL FOR SEO PURPOSE.
if ($request_uri ~ "/index.php") {
rewrite ^ /$1 permanent;
}
# REMOVE ANY MULTIPLE SLASHES IN THE URL.
if ($request_uri ~* "\/\/") {
rewrite ^/(.*) $scheme://$host/$1 permanent;
}
First rule should be replaced with separate server blocks
server {
listen 80 default_server;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
# normal config
}
Other ifs usually are not necessary. Just don't generate links with index.php and you will not need to strip it.
In the official wiki introduction it says that there are some cases which are ok. Have a look at this quote:
The only 100% safe things which may be done inside if in location
context are:
return ...; rewrite ... last;
At the end of the introduction there is an example which also features a rewrite command. So your code looks ok, too.
EDIT: You should also have a look at how the if works.
You can replace this block
# REMOVE INDEX FILES FROM URL FOR SEO PURPOSE.
if ($request_uri ~ "/index.php") {
rewrite ^ /$1 permanent;
}
with this
location ~ ^/index.php/(.*[^/])$ { return 301 $scheme://$host/$1/$is_args$args; }
location ~ ^/index.php/(.*)/$ { return 301 $scheme://$host/$1/$is_args$args; }
I also don't think you need to worry about the last rule for double // because nginx by default automatically takes care of that before it even gets to the point of matching location blocks

Redundant Nginx Location and Rewrite Regular Expression

I have a location and rewrite directive pair that works, but there is a redundancy that it seems like I should be able to optimize out. It takes an external URL like /css/20141201-styles.css and delivers /css/styles.css.
location ~ '^/(css|js)/[0-9]{8}-' {
rewrite '^/(css|js)/[0-9]{8}-(.*)$' /$1/$2;
}
It seems like I'm doing work twice, once in matching, and then again when rewriting. Is there a way to capture the matches in the location directive, and then use them in the rewrite?
location ~ '^/(css|js)/[0-9]{8}-(.*)$' {
rewrite [something here?] /$1/$2;
}
In Apache, it looks like this:
RewriteRule ^/(css|js)/[0-9]{8}-(.*)$ /$1/$2 [NC,L]
SOLUTION
Thanks to Terra for pointing out the alias directive! This location was already nested in another location which applies the root directive, so that takes care of the server path.
location ~ ^/(css|images|js)/ {
location ~ '^/(css|js)/[0-9]{8}-(.*)$' {
alias /$1/$2;
}
root /server/path/to/web/root;
}
UPDATE
This also works, and has fewer lines. The break flag on the rewrite directive prevents looping of the server level, making it just as performant as the alias solution.
location ~ ^/(css|images|js)/ {
rewrite '^/(css|js)/[0-9]{8}-(.*)$' /$1/$2 break;
root /server/path/to/web/root;
}
Solution 1: Do not create separate location, just move rewrite to other one. location / for example.
Solution 2:
location ~ ^/(css|js)/[0-9]{8}/ {
alias /server/path/to/web/root/$1/;
}

how do I rewrite a URL in nginx to an updated location?

I have the following URLs:
1) http://example.com/downloads/
2) http://example.com/downloads/widgets
3) http://example.com/downloads/gadgets
These URLs need to be redirected rewritten to the following:
1) http://example.com/products/
2 & 3 & etc) http://example.com/products/thingies
I'm currently trying the following nginx code:
location ~* ^/downloads/ {
rewrite ^/downloads/$ /products break;
rewrite ^/downloads/(.*)$ /products/thingies break;
}
It's almost working, however my site's document root is /var/www/example.com/public. So after processing the rewrite rules, nginx tries to literally serve /var/www/example.com/public/products/, whereas I want it to just rewrite to http://example.com/products/ (which then proxies to PHP and so on).
Where am I failing? Is there a different, better way to accomplish this?
Thank you for any help.
-- UPDATE --
I got it to work by using the following rules:
rewrite ^/downloads/?$ $scheme://$host/tools last;
location ~* ^/downloads/ {
rewrite ^/downloads/?$ $scheme://$host/products last;
rewrite ^/downloads/(.*)$ $scheme://$host/products/thingies last;
}
IS this the proper way of doing it in nginx? I haven't seen this rewrite rule format anywhere while researching this. It somehow seems odd.
Your update redirects, not rewrites.
Here is how I would do:
location /downloads/ {
rewrite ^ /products/thingies;
}
location = /downloads/ {
rewrite ^ /products/;
}
# uncomment if you need '/downloads' (without trailing slash) act as '/downloads/'
#location = /downloads {
# rewrite ^ /products/;
#}
The correct syntax appears to be:
location ~* ^/downloads/ {
rewrite ^/downloads/?$ /products permanent;
rewrite ^/downloads/(.*)$ /products/thingies permanent;
}

Resources