assume you want to allow users (or programs) to upload files/data/... to your website without having to write a script/cgi/... which handles the uploading. something very simple, which just stores the files somewhere so you can analyze them later. this is for example very useful to create a reporting endpoint for a content security policy without using specialized software.
if you use nginx as your webserver, there's a simple solution for this. the idea is to use the client_body_in_file_only
directive, which allows you to dump uploads to disk to pass the filename to a reverse proxy, instead of asking nginx to cache the upload and pass it on to the reverse proxy, so that it looks like a regular post
/put
to the reverse proxy.
unfortunately, this doesn't work if you use a return xxx;
instead of proxy_pass yyy;
, which would have been my preferred solution. but there's a little trick: you can ask nginx to also listen on another port, say 4000, and simply return a fixed message there. then, for the main listener (on ports 80/443), you use client_body_in_file_only
directive combined with proxy_pass http://127.0.0.1:4000
. this looks as follows:
server { listen 127.0.0.1:4000; location / { return 200 "Thank you for your report.\n"; } } limit_req_zone $binary_remote_addr zone=peripzone:10m rate=5r/m; server { listen *:80; location = /csp-reporting { # We just allow POST actions. Add PUT if you want to # support PUT as well. (Not needed for CSP reports.) limit_except POST { deny all; } # Where to store the files on disk client_body_temp_path /var/www/reports/csp/; # Store the file on disk, and don't delete it, no matter # what the proxy returns. client_body_in_file_only on; # Store at most 64k on disk. That should be sufficient # for CSP reports. client_body_buffer_size 64K; client_max_body_size 64K; # Give the client 10 seconds to upload. client_body_timeout 10s; # Do rate limiting limit_req zone=peripzone burst=20 nodelay; # Now proxy to the small internal server we started # above, and don't pass the uploaded file to it. proxy_set_body off; proxy_pass http://127.0.0.1:4000/; } }
note that i added rate limiting (see the ngx_http_limit_req_module
module), allowing on average five uploads per second for remote ips, with bursts up to 10 uploads. see the ngx_http_limit_req_module
module's documentation for more information on adding more rate limiting. you can for example also add limits per server, instead of just one per remote ip.
comments.