Look for file in subfolders in nginx - nginx

I am changing the file structure.
Some of the urls, that were previously available at root level of the site are now moved to a subfolder.
So I have an $uri.
I try_files $uri #check_subfolder;
If the file (normal .html file) still exists at the root level, or it's url is written properly, then try_files $uri works as it should.
But if the file is moved to a subfolder, then I enter
location #check_subfolder {
}
And if here I just make a redirection rewrite ^(.*) $scheme://$host/articles$1 permanent; then everything is still perfect.
But I want first to check if the $uri really exist in the /articles subfolder or not.
So I do
location #check_subfolder {
if (-f "/articles${uri}") {
rewrite ^(.*) $scheme://$host/articles$1 permanent;
}
}
It just falls down to error 404. Redirection doesn't happen. Without the if redirection works. So obviously the problem in the way how I formulate the condition.
if (-f "/articles${uri}") doesn't work.
if (-f "/articles${request_filename}") doesn't work.
if (-f "/articles/${request_filename}") doesn't work.
if (-f /articles/$request_filename) doesn't work.
if (-f /articles/$uri) doesn't work.
I obviously write wrong concatenation.

My answer is that I didn't think that -f looks for file in filesystem, not for a web-page, so I had to include $document_root.
So now it works like
location #check_subfolders {
if (-f $document_root/articles/$uri ) {
rewrite ^(.*) $scheme://$host:8090/articles$1 permanent;
}
}

Related

How to add prefix to html file name in nginx?

I have a front-end folder. For example, there is an index.html file and its German copy, de_index.html. For any html file, there is a version with the de_ prefix.
I want to make it so that, for example, when a user requests an index.html page and they have the lang=de cookie, nginx should return de_index.html. And for example, if the user requests about.html, then the server will give him de_about.html.
To begin with, I decided to try to simply replace all *.html files with their de_ version. And added the following block to the nginx configuration.
location ~ \.(html|htm)$ {
if ($uri !~ \/de_(\w)*.(htm|html)$) {
rewrite "(?<=\/)(\w*).(html|htm)$" de_$1.$2 break;
}
}
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
try_files $uri $uri/ /index.php?$args;
}
The purpose of the first block is:
If the location has .htm or .html at the end
If the $uri file does not have the de_ prefix yet
Then change $uri to the same one, just add the de_ prefix to the file name.
But maybe I did something wrong or I don’t understand the meaning of rewrite, because I get a 404 error.

NGINX conditional Rewrite extensionless URLS

I am trying to provide extensionless URLs for a client. The systems URLs will be generated without the extension in the navigation elements and links so I will have links that look like.
www.somesite.com
www.somesite.com/foo
www.somesite.com/foo/bar
www.somesite.com/bar/foo/barfoo
lets pretend for a moment that the calls will be either routed to a proxy that can handle a defined file extension or simply serve the html page if it exists. If the url is correctly rewritten then I would think a location command with a matching regex for the extension should work.
so behind the scenes we have.
www.somesite.com/index.abc
www.somesite.com/foo.def
www.somesite.com/foo/bar.abc
www.somesite.com/bar/foo/barfoo.def
...
with Apache .htaccess I can solve this problem by first testing for the existence of the page with a desired filetype.
RewriteCond %{REQUEST_FILENAME}.abc -f
RewriteRule ^(.*)$ $1.abc [L]
I would also make sure that directory browsing is off and that trailing slashes would be removed
#ensure trailing slash is removed
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)(?:/)$ $1 [R=301,L]
all well and good for Apache, and for me relatively intuitive, but this is NGINX and quite frankly I have no idea how to solve this use-case.
All the similar use cases I have found deal with html & php (How to remove both .php and .html extensions from url using NGINX?) and simply use try_files until they fall-through to a named location that rewrites the uri with .php extension. This would work if one is only dealing with a single dynamic language and fails miserably if we have two dynamic languages.
So the question is how do I do something similar in NGINX like can be done with the .htaccess condition/rewrite above
any help would be appreciated!
Cheers
Gary
UPDATE:
I have been able to get it "mostly" working by using the standard php approach. The issue is www.somesite.com is being directed to www.somesite.com/.php instead of serving the default document. Trailing slashes are also being removed correctly.
so to recap:
www.somesite.com - not working - www.somesite.com/.php
www.somesite.com/foo - working
www.somesite.com/foo/bar - working
www.somesite.com/bar/foo/barfoo - working
here my config:
location / {
index index.php index.html
autoindex off;
#remove trailing slash
rewrite ^/(.*)(?:/)$ /$1 permanent;
#try html files or route to named location
try_files $uri $uri.html #php;
}
location ~ \.php$ {
...
}
location #php {
rewrite ^(.*)$ $1.php last;
}
in other posts the try_files block looks like this: try_files $uri $uri.html $uri/ #php; the problem is if I add $uri/ it will work for the default document e.g. serve www.somesite.com but all other urls like www.somesite.com/foo/ or www.somesite.com/foo/bar/ , which are also directories and have files of the same name, will be redirected to infinity instead of their respective pages.
Assuming that you have three ways to process an extensionless URI, you would need three location blocks. You can use try_files to test for the existence of a file by type, and cascade to the next location block in the chain, if the file is not found. See this document for details.
For example:
root /path/to/document/root;
location / {
try_files $uri $uri.html $uri/ #php;
}
location #php {
try_files $uri.php #proxy;
fastcgi_pass ...;
...
}
location #proxy {
proxy_pass ...;
}
The first block processes normal files within the document root. You probably have a location ~ \.php$ block to process PHP files, and the second block is essentially a replica. The third block sends everything else upstream.

Silly nginx rewrite issue - infinate loop

I'm totally baffled with this one. Its probably something silly, and I'm missing it after along day! Anyway, I have this rewrite rule setup in my nginx config for the site:
location / {
root /srv/www/site.co.uk/www;
index index.html index.htm index.php;
rewrite ^/(.*)/index.html$ http://site.co.uk/$1/ permanent;
rewrite ^/index.html$ http://site.co.uk/ permanent;
}
When I go to:
http://www.example.com/index.html
http://www.example.com/foo/index.html
..then it correctly sends to:
http://www.example.com/
http://www.example.com/foo/
If I comment those 2 rewrite rules out, restart nginx, then retry... the page loads fine!
Can anyone see where I'm going wrong? Maybe I'm just being blind!
You have constructed a rewrite loop.
The index directive effectively generates an internal rewrite to /index.html whenever a URL with a trailing / is presented.
One way to break the loop is to only apply your rewrite rules when the external URL contains index.html. The variable $request_uri contains the external URL and can be tested using an if directive. See this caution regarding if.
if ($request_uri ~* "/index\.html(?|$)") {
rewrite ^(.*/)index\.html$ $scheme://$server_name$1 permanent;
}
location / {
root /srv/www/site.co.uk/www;
index index.html index.htm index.php;
}

Please help me understand simple nginx rewrite issue for subdomain robots.txt

For my subdomain I wanted to point to a different robots.txt file. I had hoped the following code would work:
if ($host ~ subdomain) {
rewrite ^/favicon.ico$ /favicon.ico break;
rewrite ^/robots.txt$ /robots.subdomain.txt break;
rewrite ^/([^\/]*)?/?(.*)?$ /index.php?in1=$1&in2=$2&$query_string last;
}
favicon.ico works fine, all other extensions are rewritten to index.php just fine, but so is robots.txt.
I spent [wasted] a lot of time trying to solve it, which I did by adding the following line after the robots.txt rewrite.
rewrite ^/robots.subdomain.txt$ /robots.subdomain.txt break;
Can someone please help me why it only works when I add this line, also any improvements to my config would be welcomed if you see any obvious inefficiencies! Thank you.
This should be what you're looking for:
location / {
rewrite ^/robots.txt$ /robots.$host.txt; # rewrites robots.txt
try_files $uri $uri/ #php; # try_files serves statics and sends everything else
# to your front controller (index.php)
# files such as favicon.ico get served normally
}
location #php {
rewrite ^/([^\/]*)?/?(.*)?$ /index.php?in1=$1&in2=$2 last;
}
The only caveat is that your robots.txt needs to be named after the full host, so in the example above your www.domain.com needs to have a robots.www.domain.com.txt file in the document root. This seems a bit ugly, so I'd do it this way instead:
rewrite ^/robots.txt$ /$host.robots.txt;
and then you name your file www.example.com.robots.txt

rewrite rule nginx

Can someone help me for my nginx rewrite rule. I have the problem like this
if file not found in www.abc.com/name_dir/* it will redirect to www.abc.com/name_dir/index.php .
for example :
not found in www.abc.com/xxx/* redirect to www.abc.com/xxx/index.php
not found in www.abc.com/yyy/* redirect to www.abc.com/yyy/index.php
not found in www.abc.com/zzz/* redirect to www.abc.com/zzz/index.php
not found in www.abc.com/kk/* redirect to www.abc.com/kkk/index.php
...
the problem i have thousand of name_dir. I have nginx.conf like this
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
rewrite (^.+$) $1/
break;
}
if (!-e $request_filename) {
rewrite ^/xxx/(.*)$ /xxx/index.php?$1 last;
rewrite ^.+?(/.*\.php)$ $1 last;
}
In configuration above only redirect name_dir xxx. How rewrite rule to redirect all directory ?
Thank for your help
You want to use try_files to check for the existence of files instead of if statements here (because If's are Evil in Nginx).
To to a single directory, it would be like:
location /xxx/{
try_files $uri $uri/ /xxx/index.php;
index index.php
}
What this does is try the uri as a file first. If that doesn't work, it'll try as a directory. If neither work, it'll default to index.php of /xxx/. The extra index line is to keep it from showing a blank page if you go directly to whatever.com/xxx
Using regex, we can expand this rule to work with more than one directory:
location ~* ^(/.*)/{
try_files $uri $uri/ $1/index.php?$uri&$args;
index index.php
}
This should grab the full directory structure and rout it to the appropriate index.
abc.com/yyy/nonexistant.php ==> abc.com/yyy/index.php
abc.com/yyy/zzz/nonexistant.php ==> abc.com/yyy/zzz/index.php
If you only wanted the second example to go to yyy/index.php, use this regex in the location instead:
^(/.*?)/

Resources