PHP files being downloaded on condition

Igor Sysoev igor at
Wed Aug 3 19:32:47 UTC 2011

On Tue, Aug 02, 2011 at 03:28:16AM -0400, Samael wrote:
> Igor, to cut things short - I'd like to either pass the PHP scripts'
> execution to the fcgi processes or prevent them from being downloaded.
> In addition, I tried to prevent PHP scripts in common
> webserver-writeable directories (of course, this list will be extended)
> from being executed in order not to allow user-provided PHP files to be
> passed to php-fpm:
> if ($uri ~*
> \/(images?|system|download|upload|cache|logs?)\/(.*\/)?[0-9a-z]+\.php$)
> {
> return 404;
> }
> I set this rule: "location ~ \/[0-9a-zA-Z]+\.php$" in order to evaluate
> only PHP files with alphanumeric names as these are the only one valid
> from my perspective. Of course the rule may be improved (not allowing a
> script beginning with a number to be evaluated), but I don't think that
> this is necessary at this point.
> "location ~ (/\.|.*conf.*\.php)" - in order to prevent hidden and
> configuration files from being exposed.
> I hope I didn't do anything stupid, I'm open to suggestions :)
> Edho, thank you for your advice, clearing the browser cache did the
> trick, but still - I'd like to prevent that happening again by somehow
> guarding the PHP scripts from being downloaded because of some
> configuration error, for example.

Any "if ($uri ~* ...)" construction means that it should
be replaced with "locaiton ~* ...".

As to regex locations I personally prefer to not use them at all
for several reasons, and to use only prefix locations, such as

  location /download/ {
  location /scripts/ {

I consider regex location usage only in legacy setups.
There are several ways to prevent execution of PHP in unexpected
places. 1st, the best one is to use prefix location:

   location /scripts/ {
       fastcgi_pass    ...
       fastcgi_param  SCRIPT_FILENAME   /www/site$uri;

then anything such /images, /download, /upload will be hanlded in other
locations as static files.

If you have to use regex, then you can set SCRIPT_FILENAME to directory
separated from user uploadable content:

   location ~ \.php$ {
       fastcgi_pass    ...
       fastcgi_param  SCRIPT_FILENAME   /www/site/scripts$uri;

If /download, /upload, etc will be in /www/site/download/,
/www/site/upload, then it will be impossible to execute
/www/site/upload/hack.php, since nginx will use
/www/site/scripts/upload/hach.php instead.

The 3rd way, if you can not place scripts in separate directory, you
should proper order of regex locations:

  location ~ ^/download {
      root  /www/site;

  location ~ ^/upload {
      root  /www/site;

  location ~ \.php$ {
      root  /www/site;

Igor Sysoev

More information about the nginx mailing list