Home > Back-end >  How to return 404 when php files are accessed except the index.php file?
How to return 404 when php files are accessed except the index.php file?

Time:10-28

I'm routing everything through an index.php file. I don't want anyone to have access directly to php files in my /var/www/html directory except index.php.

I have this to disable access to php files:

location ~ /*.php {
    return 404;
}

But unfortunately I still get a 404 for my index.php file.

I'm using the following to route everything through index.php:

location / {
    try_files $uri $uri/ /index.php?$args;
}

How can I get both of these to work simultaneously?

CodePudding user response:

With your configuration you return HTTP 404 Not Found for any request containing php substring at all:

'/*'   '.'   'php'
 |      |      |
 |      |       --- 'php' substring
 |       ---------- any single char
  ----------------- 0 or more '/' chars

I don't think it is really what you mean writing it. The right regex pattern to match anything ending with .php is the \.php$ one. Check PCRE regex patterns syntax for an additional info.

To match all PHP files except index.php you can use exact match location (which have precedence over a regex matching location):

location / {
    try_files $uri $uri/ /index.php?$args;
}
location = /index.php {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    fastcgi_pass <your_PHP-FPM_backend>;
}
location ~ \.php$ { # will be used for any PHP request except 'index.php'
    return 404;
}

The same can be achieved using ^~ location modifier. If the longest matching prefix location has the ^~ modifier then regular expressions are not checked:

location / {
    try_files $uri $uri/ /index.php?$args;
}
location ^~ /index.php {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    fastcgi_pass <your_PHP-FPM_backend>;
}
location ~ \.php$ { # will be used for any PHP request except 'index.php'
    return 404;
}

If you have multiply index.php files in different directories, previous solutions won't work and you'll need to use two regex matching locations instead:

location / {
    index index.php;
    try_files $uri $uri/ /index.php?$args;
}
location ~ /index\.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_pass <your_PHP-FPM_backend>;
}
location ~ \.php$ { # will be used for any PHP request except 'index.php'
    return 404;
}

This is the only configuration where location blocks order matters. location ~ /index\.php$ { ... } should be the first or any PHP file request will be blocked with the location ~ \.php$ { ... } one.

Check location directive description and How nginx processes a request documentation page for more info. You can also check Nginx redirect all traffic to index.php, but don't allow arbitrary file access SO thread for some additional examples.

  • Related