Nginx client_max_body_size per location block (with php frontcontroller pattern)

9,307

Solution 1

If /admin/upload path is virtual, it is possible to make it work as follows:

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

location /admin/upload {
    client_max_body_size 256M;

    include inc/php.conf;
    rewrite ^(.*)$ /index.php?$args break;
}

location ~ \.php$ {
    include inc/php.conf;
}

Not the prettiest too, but works.

Solution 2

Define two php locations?

location ~ ^/admin/upload/.+\.php$
{
    client_max_body_size 256M;
    include /etc/nginx/conf.d/php-fpm.conf;
}   
location ~ \.php
{
    include /etc/nginx/conf.d/php-fpm.conf;
}

Perhaps not the prettiest... Should be functional though..

Solution 3

Using multiple locations is possible, but is a bit tricky.

If you use try_files or rewrite as explained above, then the client_max_body_size would be set to the client_max_body_size of the higher context, not really the one for the location block you'd expect it to.

Move your PHP FastCGI configuration into a file that you can include, such as php-conf.conf.

Then use such a configuration:

    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php$query_string;
    }

    location ~ ^/admin/upload$ {
        client_max_body_size 4m;
        include /etc/nginx/php-conf.conf;
        fastcgi_param SCRIPT_FILENAME $realpath_root/index.php;
    }

    location ~ ^/index\.php(/|$) {
        include /etc/nginx/php-conf.conf;
        internal;
    }

Note that you need to overwrite SCRIPT_FILENAME to use index.php if you have a different script name set. This could happen because of fastcgi_split_path_info ^(.+\.php)(/.*)$;.

Share:
9,307
Jurian Sluiman
Author by

Jurian Sluiman

Updated on September 18, 2022

Comments

  • Jurian Sluiman
    Jurian Sluiman almost 2 years

    I am looking for a solution for this problem. I understand the reasoning why the setup in that question does not work, but I try to get to a solution where I can get it working.

    The idea is to allow large file uploads only on certain urls. I can use a location block for this, but the problem is: I have a php frontcontroller pattern:

    location ~ \.php {
        # ...
        fastcgi_pass unix:/tmp/php5-fpm.sock;
    }
    

    My total config looks like:

    # ...
    
    http {
        # ...
    
        client_max_body_size 512K;
    
        server {
            server_name example.com;
            root        /var/www/example.com/public;
    
            location / { 
                try_files $uri /index.php?$query_string;
            }
    
            location /admin/upload {
                client_max_body_size 256M;
            }
    
            location ~ \.php {
                # ...
    
                fastcgi_pass unix:/tmp/php5-fpm.sock;
            }
        }
    }
    

    As I understand, only one location block will be applied. So if I have a default request size of 512K, the 256M will never be applied since all requests are matched through the frontcontroller pattern ~ \.php.

    Am I right in this case and if so, what can be configured such that visitors cannot upload anything except when they upload to admin/upload?