ruby-on-railsnginxx-accel-redirect

Nginx + Rails + sendfile : file not found


Been having a problem setting up sendfile for nginx+rails lately. We have one kind of file download that's already handled by nginx, and we wanted to add a second rule to deal with another kind of files at another location, but we have no success so far.

Ruby controller :

def download_file
  send_file("/srv/www/myapp/shared/tmp/directory/file.zip")
end

Environment configuration file:

Rails.application.configure do
  # ..  
  config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
  # ..
end

Nginx configuration :

upstream myapp {
  server 127.0.0.1:9292;
}

server {
  listen 80;    
  server_name myapp.tld;

  client_max_body_size 10M;

  root /srv/www/myapp/current/public; 

  # This first block works perfectly
  location /__working_file {
    internal;
    alias /var/lib/myapp;
  }    

  # This second block does not work at all
  location /__new_files {
    internal;
    alias /srv/www/myapp/shared/tmp/directory;
  }

  location / {
    root /srv/www/myapp/current/public;
    try_files $uri @app;
  }

  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;

    proxy_set_header X-Sendfile-Type X-Accel-Redirect;
    # This first rule works perfectly
    proxy_set_header X-Accel-Mapping /var/lib/myapp/=/__working_file/;
    # This second rule doesn't
    proxy_set_header X-Accel-Mapping /srv/www/myapp/shared/tmp/directory/=/__new_files/;

    proxy_pass_header Server;
    proxy_read_timeout 300;

    proxy_pass http://myapp;
  }
}

Result

When accessing the controller action, the send_file command is triggered, then we get a "File not found" in the browser, nothing gets downloaded, and the rails log shows this:

Sent file /srv/www/myapp/shared/tmp/directory/file.zip (0.4ms)
Completed 200 OK in 169ms (ActiveRecord: 37.5ms)
Started GET "/srv/www/myapp/shared/tmp/directory/file.zip" for 109.190.197.126 at 2018-11-20 11:34:44 +0100

ActionController::RoutingError (No route matches [GET] "/srv/www/myapp/shared/tmp/directory/file.zip"):

The file does exist and is readable but nginx can't seem to access it. Any idea?


Solution

  • The problem comes from the way the two X-Accel-Mapping are set. Rack is indeed able to deal with several mappings since the merge of this PR #1187.

    However, as of today, this PR has been merged on master but not released yet (2.0.6 is currently the latest release).

    The only thing is, the correct way of setting several mappings is by using one single proxy_set_header rule, and separate each mapping with a comma, like this:

    proxy_set_header X-Accel-Mapping, /var/lib/myapp/=/__working_file/,/srv/www/myapp/shared/tmp/directory/=/__new_files/