Authorize file upload requests with nginx

I use nginx for most of my projects. It's a fast and robust HTTP server for serving static contents, and a great reverse proxy for serving dynamic pages from a web application.

I recently worked on system where users upload large data files for analysis. To protect the web application from unauthorized uploads, potentially blocking legitimate use of the service, upload authorization is a requirement.

It turns out that authorization of uploads is quite easy to implement, as nginx can do request authorization using the Auth Request module.

This nginx module implements authorization based on sub request result. Hence, a request to a given url is authorized by a subrequest to another url, for example an internal authorization url to your web app.

If you're running a system with a nginx version prior to version 1.5.4, you need to compile nginx from source to use the Auth Request module.

You can follow the instructions below, on how to compile and configure nginx with the Auth Request module.

Building nginx from source

These instructions have been tested on recent Ubuntu distributions.

Get build tools and source package

Install build pre-requsites and nginx config files etc.

 sudo apt-get install build-essential libpcre3-dev \
              zlib1g-dev libssl-dev nginx-common

Download the nginx source package.

 apt-get source nginx

For versions prior to 1.5.4

If the source package contains a version of nginx that is older than version 1.5.4, the Auth Request module is not included with the source code. You then have to download and unpack the Auth Request module's source code.

 wget http://mdounin.ru/hg/\
          ngx_http_auth_request_module/archive/tip.tar.gz
 tar xzf tip.tar.gz
 rm tip.tar.gz

Build nginx

Enter the nginx source path (note: version specific).

 cd nginx-1.1.19

You may have to edit the file auto/cc/gcc, removing the compiler option Werror. This is necessary on some (older) systems to complete the build, which will otherwise fail due to a harmless compiler warning.

Create the makefiles, selecting the modules to include in the build. See the nginx wiki for a complete list of modules, or just use my suggested list.

 ./configure --prefix=/etc/nginx \
     --conf-path=/etc/nginx/nginx.conf \
     --error-log-path=/var/log/nginx/error.log \
     --http-client-body-temp-path=/var/lib/nginx/body \
     --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
     --http-log-path=/var/log/nginx/access.log \
     --http-proxy-temp-path=/var/lib/nginx/proxy \
     --lock-path=/var/lock/nginx.lock \
     --pid-path=/var/run/nginx.pid \
     --with-http_gzip_static_module \
     --with-http_ssl_module --with-ipv6 \
     --without-http_browser_module \
     --without-http_limit_req_module \
     --without-http_limit_conn_module \
     --without-http_map_module \
     --without-http_memcached_module \
     --without-http_referer_module \
     --without-http_scgi_module \
     --without-http_split_clients_module \
     --without-http_ssi_module \
     --without-http_userid_module \
     --without-http_uwsgi_module \
     --with-http_auth_request_module

If you're building a nginx version prior to 1.5.4, just replace the last line with the path the downloaded version of the Auth Request module (note: version specific).

--add-module=../ngx_http_auth_request_module-662785733552

Build the binary and copy it to the right directory (note: there is no need for make install as the config files etc. are already installed with the nginx-common package):

 make
 sudo cp objs/nginx /usr/sbin/

Configuration

After building and installing nginx with the Auth Request module, all that is left, is to change the configuration files to suit your needs.

Edit the /etc/nginx/nginx.conf and /etc/nginx/sites-available/default configuration files. See the nginx docs for documentation about the different options.

Specifically, see configuration options for the Auth Request module.

The default settings nginx accepts POST and PUT requests containing up to 1Mb of data in the request body. This limit is configurable using the client_max_body_size parameter see nginx docs.

Create a symlink to the default site

 sudo ln -s -t /etc/nginx/sites-enabled/ /etc/nginx/sites-available/default

Start nginx

 sudo invoke-rc.d nginx start

Finally, you now have nginx running with the auth request module.