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.
Be the first to comment.
Copyright James Gardner 1996-2020 All Rights Reserved. Admin.