My team was working on a CMS solution based on Django, and we needed to have private files. Those files are also video files which we would like to stream to HTML5 player. The problem was, Django is not nginx or apache. It’s even wrong to want it. We were sad our private files are served slowly without streaming features and actually not working in every browser.
Because of the last issue, we were forced to look for a solution, and we were
surprised it was fixed a long time ago with a very sexy solution! In nginx,
it’s called X-Accel,
but usually, you can find it as X-Sendfile
.
Because I didn’t know about it before and wasn’t able to set it up correctly for the first time, I decided to share it with you. :-)
It’s just a new section in nginx and special header in your application. Usually, without this feature, you would set up a handler in your app, check permission and return data directly. With X-Accel, you don’t return data, but the special header.
Let’s say you want to have two URL in your app, /media
for public media and
/smedia
for private media. Then in your nginx you will need a usual section
for public media and two new sections for private ones. /smedia
is visible
outside and headed to your app, and /pmedia
is visible only internally thanks
to internal
configuration.
location /media/ {
alias /data/media/public/;
}
location /smedia/ {
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:/var/run/app/uwsgi.sock;
}
location /pmedia/ {
internal;
alias /data/media/private/;
}
Now you need only to update your app not to return actual data, but header with
/pmedia
location. When nginx finds in the response X-Accel-Redirect
header,
it will use this new location. Because this new location is returned from the
(internal) app, it will also allow using internal locations.
For example, in Python with a Flask it could look like:
@app.route('/<file_id>')
def serve_private_media(file_id):
# check access to the file
response = make_response()
response.headers['X-Accel-Redirect'] = '/pmedia/path/to/file'
return response
Note that path is starting with /pmedia
and then the path is relative to the
root of the directory with private data, in our example to /data/media/private/
.
And that’s it!