Nginx and File Upload Progress
Keeping in philosophy of KISS, nginx is an awesome, simple web server. It does few things and does it extremely well.
It doesn’t do CGI but does proxy’ing and that makes it extremely useful as a front end web server. I recently had to implement an extjs based progress bar for large file uploads with nginx acting as a front end to a Rack/mongrel based application. Here are the steps for ubuntu.
Do not install nginx from the repo. Uninstall if it’s already installed.
apt-get remove nginxmkdir -p /opt/downloads cd /opt/downloads
Download nginx sources from nginx.net and unpack (I’m working with nginx-0.6.36):
tar zxf nginx-0.6.36.tar.gz
Download an untar upload progress module from nginx wiki
tar zxf Nginx_uploadprogress_module-0.5.tar.gz cd nginx-0.6.36 ./configure --prefix=/opt/nginx --add-module=/opt/downloads/nginx_uploadprogress_module make install
This’ll install nginx in /opt/nginx
Configuration
open up /opt/nginx/conf/nginx.conf and add following lines:
http { client_max_body_size 30M; # adjust as per your need upload_progress proxied 1m; server { server_name my.server.com; listen 80; root /var/www/nginx-default/my-static-files; location /ajax { proxy_pass http://localhost:2300; proxy_redirect default; track_uploads proxied 30s; } location ^~ /report_file_uploads { report_uploads proxied; } } }
This assumesĀ ‘/ajax’ is the backend application proxy.
In Javascript, to get progress bar going, send following AJAX message in a loop, after the form with file upload field has been submitted.
Lots of details are omitted since these are dependent upon your javascript library of choice (which, btw, for us is extjs).
var upload_id = 'MyUniqueID'; // upload_id must be unique for each upload session this.send_ajax_message({ url: '/report_file_uploads', headers: {'X-Progress-ID' : upload_id}, method:'GET', success: function(r) { r = this.parse_ajax_response(r); if(r.state == 'uploading' || r.state == 'starting') { var percent = (Number(r.received)/Number(r.size)); if(percent > 1.0) percent = 1.0; //show percent as you wish on your progress meter // sleep for few seconds and send this ajax message again } else if(r.state == 'done' || r.state == 'error') { // kill your loop timer // finish your progress meter } } });
Let me know if you’d like javascript fragment for extjs and I’ll post it but it’s relatively straightforward.
At Yellowfish, we specialize in web2.0 Ajax web application development using open source tools and modern software trends.

June 18th, 2009 at 7:06 am
[...] Nginx and File Upload Progress (tags: nginx web sysadmin) [...]
September 12th, 2009 at 5:28 am
Thanks! This article helps me
September 23rd, 2009 at 1:52 pm
When i define location /ajax it doesn’t send upload progress to client, and if i define location / it doesn’t want to display root index file but upload progress is working. What’s the problem and could you explain your /ajax backend more?
September 23rd, 2009 at 2:46 pm
If you defined ‘location /ajax’ as given above, the issue probably is with your javascript. Here’s my Ajax javascript code that submits the form:
var unique_id = generate_guid(); // you can find javascript GUID library on the Net Ext.Ajax.request({ url: '/ajax/files', params: {'X-Progress-ID':upload_id}, // this is important success: function(r) { alert('saved') } });The ‘/ajax/files’ simply maps to a controller which retrieves file submitted normally – in a ‘param’. Nothing special goes on here.