Nginx 404 instead of 403 for empty directory

nginxphp-fpmphp5web-server

I have the following config for my nginx server:

server {
    listen 80 default_server;
    server_name example.com www.example.com;
    root /var/www/example.com/web;

    index index.php index.html;

    location / {
        # try to serve file directly, fallback to rewrite
        try_files $uri $uri/ @rewriteapp;
    }

    location @rewriteapp {
        # rewrite all to index.php
        rewrite ^(.*)$ /index.php last;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
    }
}

And the following directory structure:

/var/www/example.com/:

  1. /index.php
  2. /dir/index.html
  3. /empty/

When client hits: 'example.com/dir/' then index.html is served.

When client hits some non-existent URL like this: 'example.com/non-existent/' then index.php is served in the root directory.

But when client hits: 'example.com/empty/' then 403 status code is sent.

  1. Why it's sending 403 when 404 is more appropriate cause index file is missing in this directory?
  2. How do I map such requests to index.php (@rewriteapp)?

Best Answer

  1. This happens because, in most web servers, the default action for folders is "Directory listing" which is disabled by default. The same would happen in Apache usually if you disable Directory indexing. What you can do in nginx is to put =404 at the end of your try_files directive.

  2. You can do this by putting /index.php at the end of the try_files directive. However, due to security reasons, this is not always recommendable.

Also, there is a small misunderstanding of nginx in your configuration: you should replace $uri/ with $uri/index.php or $uri/index.html or whatever. It stops at try_files $uri/ because it does find that location but the user is forbidden to access it.