Log in

No account? Create an account
Configuring nginx to serve files big password-protected files for Rails 1.1.6 - Chaz Meyers [entries|archive|friends|userinfo]
Chaz Meyers

[ website | chazmeyers.com ]
[ profile | view profile ]
[ archive | view archive ]

[Links:| chazmeyers.com Twitter ]

Configuring nginx to serve files big password-protected files for Rails 1.1.6 [Mar. 21st, 2008|02:53 pm]
Chaz Meyers
I spent about 3 days figuring out how to do this right, so I figured I might as well save someone else the headache.

I assume that:
  • your files are at /mass-storage/protected-files/
  • you're starting off with Ezra's nginx configuration
  • you want to serve files at http://localhost/files/your/path/here via a FilesController

First, you need something like this in your routes.rb:
map.connect 'files/*path_info', :controller => 'files', :action => 'index'

This will send the extra path stuff into a path_info variable without any additional parsing.

Next, you'll want to add this to your nginx.conf after your "location /" block:

location ^~ /protected-files/ {
  root /mass-storage

This registers /protect-files urls which will serve from /mass-storage/protected-files, but can only be accessed via the magic X-Accel-Redirect header that nginx understands.

A minimal FilesController might look like this:
class FilesController < ApplicationController
  def index
    # insert any permissions check here
    path = params[:path_info]
    response.headers["Content-Type"] = "application/octet-stream"
    response.headers["Content-Disposition"] = "attachment; filename=\"#{File.basename(path)}\""
    response.headers["X-Accel-Redirect"] = "/protected-files/#{path}"
    response.headers["Content-Length"] = File.size("/mass-storage/protected-files/#{path}")
    response.headers["Status"] = "200 OK"
    response.body = ""
    @performed_render = true

I'm setting @performed_render and response.body by hand because if you render :nothing in Rails 1.1.6, it clobbers your Content-Length. Nginx does not touch any of the headers I set. Later versions of Rails fixed this, so you should render :nothing in newer versions!

You might want your file path to be /mass-storage/files and your internal url to be /files to match what people are typing into their browser, but you must resist! When I tried this, nginx seemed to get confused and would just raise a 500 because it thought it was stuck in a redirection loop.

[User Picture]From: pabirdguy
2008-03-22 02:31 pm (UTC)


stop talkin' jibberish man! :-)
(Reply) (Thread)