Prevent large file upload with nginx

5,583

Useful information here: https://stackoverflow.com/questions/4947107/nginx-upload-client-max-body-size-issue

I quote part of the most interesting answer (for my case):

Most clients don't read for responses until the entire request body is sent. Because nginx closes the connection the client sends data to the closed socket, causing a TCP RST.

If so it's only a browser problem that will not affect (overload) my web server. It seems to complain with my memory inspection that showed both nginx and php-fastcgi haven't been truly overloaded when uploading a large (700mb) file.

I could address the browser problem in several ways, for example:

  • add a <input type="hidden" name="MAX_FILE_SIZE" value="5242880" /> in my form
  • use a custom 413 nginx error page
Share:
5,583

Related videos on Youtube

Luciano Mammino
Author by

Luciano Mammino

Co-Author of "Node.js Design Patterns (Packt)" (https://www.nodejsdesignpatterns.com/) I am a Software Engineer born in 1987, the same year that the Nintendo released “Super Mario Bros” in Europe, which, by chance is my favourite game! My primary passion is code and I am extremely fascinated by the web, smart apps and everything that's creative like music, art and design. I started coding at the age of 12 using my father's old Intel 386 with provided with the DOS operative system and the qBasic interpreter. I have a Master Degree in Computer Science and during the years I developed my engineering skills mostly as Web Developer. I consider myself an expert Php developer and I commonly adopt Open Source libraries and frameworks such as Symfony2 and Doctrine, but I also love Javascript, both client side (jQuery/Angular) and server side (NodeJs). In the last 3 years I have been very close to the entrepreneurship world, working with different startups. I ended up being a co-founder of an ambition fashion-tech startup: Sbaam.com. With Sbaam I had chance to attend several events, competitions and acceleration programs in Italy and in Ireland.

Updated on September 18, 2022

Comments

  • Luciano Mammino
    Luciano Mammino almost 2 years

    I'm serving my website using Nginx as web server. I offer upload functionality to my users (they are allowed to submit pictures up to 5Mb) so I have the directive: client_max_body_size 5M; in my server config. What I've noticed is that if I try to upload any file the webserver does not prevent the upload of bigger files. Just as example, suppose I try to upload a really big video (a movie) of 700Mb. The server does not reject the upload instantaneously but it buffers the whole data (taking so long and slowing down the server) and only at the end of the upload it returns a 413 Request entity too large error.

    So the question is: is there any way to properly configure Nginx to block big files upload when the transmitted data starts to overcome my client_max_body_size limit?

    I think it would be really insecure to go on production with my actual settings and I wasn't able to find anything helpful on google.

    Edit:

    I'm using php and Symfony2 as backend...

    Edit (again):

    This is what appears in my error.log:

    2013/01/28 11:14:11 [error] 11328#0: *37 client intended to send too large body: 725207449 bytes, client: 33.33.33.1, server: www.local.example.com, request: "POST /app_dev.php/api/image/add/byuploader HTTP/1.1", host: "local.example.com", referrer: "http://local.example.com/app_dev.php/"`
    

    The weird things is that i am monitoring my nginx error.log with tail -f error.log and the message appears immediately when the upload starts (before it ends). So nginx makes some kind of preventive check, but it doesn't stop/chunk the upload request...

    I also tried to verify if php gets the control of the upload by issuing a echo 'something'; die(); on the page who handles the upload but it didn't printed out anything and didn't stopped the upload request. So it should be nginx or some php internals that make the whole upload continue until it's completely transmitted...

    another edit: here's a view of my top (monitoring nginx and php) when a big file upload is in progress (nginx gets overloaded): top: monitoring php and nginx

    edit: here's my nginx configuration

    server {
        listen   80;
        server_name www.local.example.com local.example.com;
        access_log /vagrant/logs/example.com/access.log;
        error_log /vagrant/logs/example.com/error.log;
        root   /vagrant/example.com/web;
        index app.php;
        client_max_body_size 6M;
    
        location /phpmyadmin {
            root /usr/share;
            index index.php;
            location ~* \.php {
                fastcgi_intercept_errors on;
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_split_path_info ^(.+\.php)(/.*)$;
                include fastcgi_params;
                fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
                fastcgi_param  HTTPS              off;
            }
        }
    
        location / {
            try_files $uri @rewriteapp;
        }
    
        location @rewriteapp {
            rewrite ^(.*)$ /app.php/$1 last;
        }
    
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ ^/(app|app_dev)\.php(/|$) {
            fastcgi_intercept_errors on;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            fastcgi_param  HTTPS              off;
        }
    }
    
    • David Schwartz
      David Schwartz over 11 years
      Are you sure it's Nginx that's buffering the file?
    • Luciano Mammino
      Luciano Mammino over 11 years
      Updated my question with a specific test to verify if it's an nginx or php behavior that handles upload this way...
    • Harrys Kavan
      Harrys Kavan over 11 years
      2 things, if you want to make a image uploader, you sould check the fileextension and only allow image extencions. you should doublecheck the size. it sounds like php does not give up and forces somehow to load up the file.
    • David Schwartz
      David Schwartz over 11 years
      @LucianoMammino: Is is the nginx process that's using the memory? It's memory consumption that's the problem, right?
    • Luciano Mammino
      Luciano Mammino over 11 years
      @DavidSchwartz honestly i don't know how to check if it's nginx or php-fm that consumes up the memory. It's not only about memory consumption but also about slowing down the whole server (many users could issue big file uploads simultaneously)
    • Luciano Mammino
      Luciano Mammino over 11 years
      @DavidSchwartz, added a screenshoot...
    • David Schwartz
      David Schwartz over 11 years
      nginx only has like 2.5MB resident. So it's not an nginx problem.
    • Harrys Kavan
      Harrys Kavan over 11 years
      @Luciano you should try to improve you php code, i guess it's php blocking the abort of the ngnix
    • Luciano Mammino
      Luciano Mammino over 11 years
      @DavidSchwartz so, are you saying it's a php5-cgi problem? how to dig further? I have no clue on how configuring php-cgi (if it creates the problem) to avoid this issue...
    • Luciano Mammino
      Luciano Mammino over 11 years
      @derty how can my php code blocking nginx abort? What configuration value should I check?
    • Harrys Kavan
      Harrys Kavan over 11 years
      No configuration, try to improve your code, so php checks if the file is to big, and if it is so, do not start the upload.
    • Luciano Mammino
      Luciano Mammino over 11 years
      @derty: I don't think I can actually perform any preventive check from php. As I said, I have added a die() that should have stopped everything (despite of the uploaded file) but the upload kept running until the end and then i got the default 413 nginx error page... My php code seems to not being executed at all. I'm really welcome to some idea about how to properly test this behavior (if you think my test is not appropriate)...
    • Harrys Kavan
      Harrys Kavan over 11 years
      Your application do have a formular or some kind of upload interface. And before this interface gives the command to start the upload, you should verify (as part as a "validation" if the file that is going to be uploaded is aceptable for you). If it is bigger then xMB you should give an error (file is to large). Do you understand?
    • Luciano Mammino
      Luciano Mammino over 11 years
      Thanks @derty, I just used symfony2 default upload code (closer to the one shown in the response here: stackoverflow.com/questions/11037115/…) but nothing changed... it still seems to never hit php code!
  • Luciano Mammino
    Luciano Mammino over 11 years
    I have the following settings for these 2 config values: upload_max_filesize => 5M => 5M and post_max_size => 8M => 8M (taken with php -i from command line)
  • Harrys Kavan
    Harrys Kavan over 11 years
    have a look at the .htaccess in the root folder of you website. there might be some more modifications to. the definitions in the .htaccess are more dominant IF there are some. Are you hiding your Website behind a proxy?
  • Luciano Mammino
    Luciano Mammino over 11 years
    I do use nginx so no .htaccess files :)
  • Harrys Kavan
    Harrys Kavan over 11 years
    I would reupload a large sized file and have a look at the log's. try to find the message where it stops to upload and have at this information. Feel free to post it here so we might find out a little more
  • Luciano Mammino
    Luciano Mammino over 11 years
    Just updated my question to add additional informations about what appears in my logs