Private Downloads with attachment_fu and nginx

So, you’re using attachment_fu to handle user file uploads in your rails app, right? If you’re also using Nginx for your web server, here’s a quick and dirty way to do controlled file access in less than 10 lines of code.

Now, the documentation for attachment_fu indicates that the standard way to do downloads using the file system store is Attachment#public_filename. That works great, if you’re comfortable with relying on somewhat obfuscated URLs for privacy, and nothing else. You can always do something like this in your view:

<%= link_to @attachment.filename, @attachment.public_filename -%>

So how do we add some access control to this? Let’s start with your AttachmentsController, and add a #show action.

def show
  @attachment = current_user.attachments.find(params[:id])
  # Do some other stuff if we need to
  head(:x_accel_redirect => @attachment.public_filename,
       :content_type => @attachment.content_type,
       :content_disposition => "attachment; filename=\"#{@attachment.filename}\"")

The X-Accel-Redirect header tells nginx to serve up the assigned path directly, letting Mongrel get on to serving the next request.

Now, in your nginx.conf, you need to configure your attachments path, which should work something like this (inside your main server section).

location /attachments {
  root /var/www/myapp/public;

You’ll want to replace the root directive with the actual path to RAILS_ROOT/public. The internal keyword tells nginx that it should only serve up files under that location when directed to via X-Accel-Redirect.

Hope this helps.

Spread it: add to|Digg it|add to ma.gnolia|Stumble It!||post to facebook


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: