4

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)?
Slava Fomin II
  • 1,701
  • 4
  • 17
  • 23

3 Answers3

11
  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.

Florin Asăvoaie
  • 7,057
  • 23
  • 35
  • 1
    Thank you for your answer! However, **@rewriteapp** is in the end of my **try_files**, but it looks like it's not reaching it. Looks like it stops trying on **$uri/**. – Slava Fomin II Jul 05 '14 at 09:16
  • 1
    Ah, I see it now, you should replace $uri/ with $uri/index.php or $uri/index.html or whatever. It stops because it does find that location but the user is forbidden to access it. – Florin Asăvoaie Jul 05 '14 at 09:34
  • Oh, it makes sense. Please update your answer and I will be glad to accept it. Thanks! – Slava Fomin II Jul 05 '14 at 10:26
  • Careful: this might bypass some of the later `location` rules within a block. I had a redirect on a certain `/folder/` location that was ignored because of this. Instead, I'm now using the other solution: http://serverfault.com/a/673513/121774 – Ruben Verborgh Oct 12 '16 at 09:24
3

If you want to make nginx send a 404 whenever it would otherwise have sent a 403, that's done with error_page:

server {
    root /var/www/example.com/web;
    error_page 404      /s/404.html;
    error_page 403 =404 /s/404.html;
    location /s/404.html { internal; }

    # etc
}

The location line makes http://example.com/s/404.html produce a 404 as well.

zwol
  • 1,355
  • 2
  • 12
  • 22
  • As you said, this is just replacing the 403 error page with 404. Is it possible to do this only in the case of directory index pages? 403 can mean other things than "you're not allowed to see the directory index". – Steen Schütt May 19 '15 at 15:16
0

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.

This works for me as it was approved as correct answer :)

Thanks Florin Asăvoaie

location ^~ /folder_of_prefix {
        alias /home/user/html;
           try_files  $uri/index.html  =404;

    }