How nginx process =404 fallback in try_files - nginx

I have a example web server with only one index.html file in a www directory. I can setup a nginx with following configuration:
location /subfolder {
alias /data/www;
try_files $uri $uri/ /index.html;
}
In browser I can see correct response on my local domain test.local/subfolder, also test.local/subfolder/something returns a default nginx page (it is normal because root is not set)
if I change a configuration to
location /subfolder {
alias /data/www;
try_files $uri $uri/ /index.html =404;
}
response to test.local/subfolder is still correct, but test.local/subfolder/something and all URI with /subfolder prefix return a index.html of correct response also status is 200 not 404. If I remove /index from try_files I get the same result
I wonder how nginx process request with =404 fallback, but cant find any information, not even in a official docs.
UDAPTE:
I found out that a alias directive should end with an / but still dont get a =404 functionality and purpose because a status is still 200ok

The try_files directive only supports these syntaxes:
try_files file ... uri;
try_files file ... =code;
It doesn't support:
try_files file ... uri =code;
The difference between file and uri here, is that for file arguments, NGINX will check their existence before moving on to next argument; for uri, it won't.
If the last argument has form of a =code, then all prior arguments to it are files (checked for existence).
From this, you can get a conclusion that with request URI /foo/bar and this config:
root /var/www;
location /foo/ {
try_files $uri $uri/ =404;
}
... Will not trigger 404 error if any of the files exist:
/var/www/foo/bar
/var/www/foo/bar/ directory (if you have autoindex enabled)
/var/www/foo/bar/index.html (or index.php, etc.) (due to value of index)
Only when none of the above exist, NGINX will trigger 404 error.

You should define the root of your server, then the default indexes and then add the =404 to try_files:
server {
server_name example.com;
root /var/www/html/example.com;
index index.html index.htm index.php;
# This is optional - if you want a customized 404 error page
error_page 404 /404.html;
location /subfolder {
try_files $uri $uri/ =404;
}
}
The difference between root and alias is that root appends location to get the absolute path in the filesystem while alias excludes the location. So for example when you try to fetch http://example.com/subfolder/filename.txt
server_name example.com;
root /var/www/html/example;
location /subfolder {
try_files $uri $uri/ =404;
}
will return the contents of /var/www/html/example/subfolder/filename.txt (if it exists) while
server_name example.com;
location /subfolder {
alias /var/log;
try_files $uri $uri/ =404;
}
will return the contents of /var/log/filename.txt (if it exists)

Related

is try_files processing context in named location different from normal location?

I have the flow nginx config:
server {
listen 80;
location / {
root /mypath/p1/;
try_files $uri $uri/ #verify;
}
location #verify {
root /mypath/p2/;
try_files $uri $uri/ /index.html;
}
}
/mypath/p1/ directory contains the file index.html, but /mypath/p2/ not.
when i request a file which not exists in all the two directories, nginx return the /mypath/p1/index.html content.
If i modify #verify location to:
location #verify {
root /mypath/p2/;
try_files $uri $uri/ /index.html =404;
}
when i request a file which not exists in all the two directories, nginx return 404.
According to the nginx docs : try_files :
the processing is performed in the current context. The path to a file is constructed from the file parameter according to the root and alias directives.
But, in the named location #verify, the result is that:
if use =404, the result as the docs describes
if not use =404, return index.html with parent context path
and i can not find any docs with the context change description.
Any one can help me to confirm the action?
Sorry, it was my own stupidity.
If use =404, /index.html is treated as a file, so return 404
If not use =404, /index.html is treated as a URL(because it is the last one), it redirects to the https://my.domain.com/index.html, and then math the root location.

Getting 500 internal error on redirect rule of alias in nginx

I am newbie to nginx server. I am getting stuck in URL redirection. I have following lines to default file.
server {
listen 80;
root /home/ubuntu/web/server/current/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name _;
error_log /home/ubuntu/web/error.log info;
location / {
# try_files $uri $uri/ /index.php?$query_string;
# try_files $uri $uri/ =404;
}
rewrite ^/web/(.*) /web/;
location /web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
what I expect from above rewrite rule is - all URLs like - http://example.com/web/login, http://exmpale.com/web/dashboard will be redirected to /home/ubuntu/web/client/web/ and the default page to hit is index.html file.
When I open the error log file then i found error like -
rewrite or internal redirection cycle while internally redirecting to "/web/index.php", client: ip_address, server: _, request: "GET /web/ HTTP/1.1", host: "ipaddress"
What i am doing wrong here.
Answer credit goes to #RichardSmith, he provided possible error which is in right direction. I figure out my mistake in nginx rewriting rule.
rewrite ^/web/(.*) /web/;
location /web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
Instead of above I should have following-
rewrite ^/web/(.*) web/;
location web/ {
alias /home/ubuntu/web/client/web/;
# try_files $uri $uri/ index.html;
}
Server consider path as absolute whenever / placed before web. Thus rewrite statement tries to redirect to fallback file which is not existed in absolute path. Eventually, rewrite statement makes never ending loop.

Defaulting to 404 when file doesn't exist in nginx

Here is my nginx setup:
location / {
root /var/www/web-app/public;
index index.html index.htm;
try_files $uri $uri/ /index.html;
default_type "text/html";
}
location /profile_images {
try_files $uri $uri/ =404;
}
The question is on that second block. It is a directory full of images. When I look up an image based on a user id, I may or may not have the image. If not, I want a 404 error. Based on the above I am getting a 404 on all images now. I have tried both 404 and =404.
The first location is my api which works fine.
I look up the images (in html) with src='/profiles_images/***.png'
For what it is worth, I am using reactjs.
You are missing a root directive for the second location block. Where several location blocks share the same value for root, it is usual practice to place the root statement in the enclosing server block so that all location blocks inherit the same value. For example:
server {
...
index index.html index.htm;
root /var/www/web-app/public;
location / {
try_files $uri $uri/ /index.html;
}
location /profile_images {
try_files $uri $uri/ =404;
}
}
See this document for more.

Nginx configuration for single page app and nested directories

I have a directory/files structure such as:
root/
a/
utils.js
b/
assets/
styles.css
app.js
index.html
And I want to configure nginx to serve files from a directory directly if exist and have single page app in directory b (if file in path exists the it wil be served directly, nd if not the fallback will end up at index.htm file.
For example:
myapp.com/a/utils.js will return that file.
myapp.com/b/ or myapp.com/b/foo will display index.html
myapp.com/b/assets/style.css will return directly css file
I tries multiple different configurations and non had worke so far. For exampe the simplest:
server {
listen 80;
root /root;
index index.html;
location / {
try_files $uri $uri/ /index.html =404;
}
}
I also tries something to serve different directories:
server {
listen 80;
root /root;
index index.html;
location /a {
try_files $uri $uri/ =404;
}
location /b {
try_files $uri $uri/ /index.html =404;
}
}
I tried to define different roots as well:
server {
listen 80;
index index.html;
location /a {
root /root/a;
try_files $uri $uri/ =404;
}
location /b {
root /root/b;
try_files $uri $uri/ /index.html =404;
}
}
Nginx seems to ignore existing files and ends up returning 404 page at all times. When I try to access soe existing file directly it gets redirected to / (root) url regardless.
The last parameter of a try_files statement is the default action. There can only be one. Many of your examples have two. See this document for details.
The correct URI for your index.html file is /b/index.html which is what you need to use for the default action of the try_files statement.
This should meet your requirements:
location / {
try_files $uri $uri/ /b/index.html;
}
You do not state what should happen with the URI /a/foo. In the above case, it would also return index.html. If you need it to return a 404 response, you would use:
location / {
try_files $uri $uri/ =404;
}
location /b {
try_files $uri $uri/ /b/index.html;
}
See this document for more.

Nginx multiple locations with different roots

I have really simple nginx configuration with 3 locations inside. Each of them have it's own root directory + I should be able to add another in the future easily.
What I want:
Request /admin => location ^/admin(/|$)
Request /admin/ => location ^/admin(/|$)
Request /admin/blabla => location ^/admin(/|$)
Request /client => location ^/client(/|$)
Request /client/ => location ^/client(/|$)
Request /client/blabla => location ^/client(/|$)
Request /blabla => location /
Request /admin-blabla => location /
Request /client-blabla => location /
Actual result:
All requests goes to location /.
I tried many different suggestions from docs, stackoverflow and other sources using different combinations of aliases, try_files, roots and regexes, but nothing worked for me.
Only when I tried to use just return 200 'admin'; and return 200 'front' it worked as intended.
Minimal config:
server {
listen 80;
index index.html;
location / {
root /var/www/html/www_new/front;
try_files $uri $uri/ /index.html;
}
location ~ ^/admin(/|$) {
root /var/www/html/www_new/admin;
try_files $uri $uri/ /index.html;
}
location ~ ^/client(/|$) {
root /var/www/html/www_new/client;
try_files $uri $uri/ /index.html;
}
}
Directory structure:
/admin
/client
/front
Thank you
When you change the root it'll still include the directory name, so what you want to do is only set the root for location /. You also don't need any additional regex on /admin as the location modifier ~ already tells nginx 'anything starting with'.
This works for your use case:
server {
listen 80;
index index.html;
location / {
root /var/www/html/www_new/front;
try_files $uri $uri/ /index.html;
}
location ~ ^/admin {
root /var/www/html/www_new; # the directory (/admin) will be appended to this, so don't include it in the root otherwise it'll look for /var/www/html/www_new/admin/admin
try_files $uri $uri/ /admin/index.html; # try_files will need to be relative to root
}
}

Resources