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:


  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)?
  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.

| improve this answer | |
  • 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 5 '14 at 9: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 5 '14 at 9:34
  • Oh, it makes sense. Please update your answer and I will be glad to accept it. Thanks! – Slava Fomin II Jul 5 '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: serverfault.com/a/673513/121774 – Ruben Verborgh Oct 12 '16 at 9:24

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.

| improve this answer | |
  • 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.