Home Blog CV Projects Patterns Notes Book Colophon Search

NGINX Auth

4 Feb, 2022

I regularly come across the case when programming Django where I want to serve a large static file, but only to an authorised user.

One solution is to do the check in the Django view and then to return the file in the response if the user is authorised.

This is all well and good, but Django isn't great at serving static files. NGINX is.

Wouldn't it be good if NGINX could check with Django if the user is allowed to access the file and then serve it if they are?

Well NGINX supports this. It proxies the HTTP request to the URL you set, and if a 200 OK is returned it will serve the file, otherwise it will show an error.

See https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/

Here's an example:

upstream keepalive-upstream {
    server 127.0.0.1:8000;
    # server  unix:/home/james/hello;
    keepalive 1025;
    keepalive_requests 1000000;
    keepalive_timeout 60s;
}


server {
    listen 80 default_server;
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name _;

    location /private/ {
        auth_request /auth;
        auth_request_set $auth_status $upstream_status;
        try_files $uri $uri/ =404;
    }

    location = /auth {
        internal;
        proxy_pass              http://127.0.0.1:8000;
        proxy_pass_request_body off;
        proxy_set_header        Content-Length "";
        proxy_set_header        X-Original-URI $request_uri;
    }
}

This says that the /private path should serve the files from /var/www/html/private (because this is the root directory /var/www/html with the /private path appended).

In order to serve it, a request will be made to http://127.0.0.1/auth (which is the proxy_pass location plus the /auth path). This is an internal proxy request and it doesn't need a content length.

The server in Fast HTTP Server would be suitable for testing this.

That implementation will authorise NGINX if ?auth=true is appended to the URL, not otherwise. So if you put a private.txt file at /var/www/html/private/private.txt you can test like this:

curl -v http://localhost/private/private.txt?auth=true
curl -v http://localhost/private/private.txt?auth=false

One caveat is that NGINX proxies using HTTP 1.0 by default which closes the TCP connection to the server after each request.

I've documented a setup for an HTTP 1.1 proxy set up here.

Comments

Be the first to comment.

Add Comment





Copyright James Gardner 1996-2020 All Rights Reserved. Admin.