Nginx X-Accel Explained

en in code • 3 min read
Mind the age! Most likely, its content is outdated. Especially if it’s technical.

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!






4 responses

Sir, thank you so much for this solution. You have saved me a lot of time. The top results for implementing X-Accel-Redirect with Django are plain wrong. @Alex You are welcome. Glad to here it's helpful. :-) I'm having this problem right now in Django too. I have a template that needs to be rendered with a video tag. Do you know what the video src attribute would look like when it renders?? Would the example on this page look something like /pmedia/12/filename.mp4 ??? @Mike Link on the page has to go to /smedia which is handled by the app. Django will check the permissions and return the pmedia back to nginx and nginx will handle serving the file itself. /pmedia should not be accessible directly.




You may also like

en Makefile with Python, November 6, 2017
en Fast JSON Schema for Python, October 1, 2018
en Deployment of Python Apps, August 15, 2018
cs Jasně, umím Git…, August 6, 2014
cs Checklist na zabezpečení webových aplikací, March 1, 2016

More posts from category code.
Do not miss new posts thanks to Atom/RSS feed.



Recent posts

cs Zápisky z cest: Šumava, November 24, 2024 in travel
cs O klimatizaci, November 10, 2024 in family
cs První slůvka, November 3, 2024 in family
cs Jakou knihu čteš?, October 12, 2024 in family
cs V kolik chodíte spát?, September 29, 2024 in family