📜 ⬆️ ⬇️

Ruby on Rails and Nginx: effectively giving away large files

In this post I will tell you how to properly configure Nginx to maximize the efficiency of large files from your rails application. To my surprise, I did not find such information in Russian. There are articles on the use of X-Accel-Redirect in conjunction with php, but in order to say about rails and in my native language something is not thick ... In general, I will try to fill this gap.

Task


So, the source data is as follows:


Decision


As much as I would not like to avoid references to English-language sources, but I cannot pass by official documentation. In Nginx there is a great thing X-Accel-Redirect , with the help of which our problem is solved. Now I will show you how to make it work.

In our Rails application, in the config / environments / production.rb file, you need to uncomment the line:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 

In the nginx configs you need to add:
 proxy_set_header X-Accel-Mapping /mnt/filestorage/=/private_files/; location /private_files/ { internal; alias /mnt/filestorage/; } 

Everything. Setup is complete. Let's see how it all works on the example of downloading the file. At this stage, we believe that the Nginx and Rails application are already configured and working.
')
1. Browser requests file
 # HTTP  GET /download/kino.avi HTTP/1.1 

2. Nginx receives this request and sends it to rails application, adding another header.
 #  Nginx proxy_set_header X-Accel-Mapping /mnt/filestorage/=/private_files/; 

 # HTTP  GET /download/kino.avi HTTP/1.1 X-Accel-Mapping: /mnt/filestorage/=/private_files/ 

3. The application's rails controller checks if the file can be given to this user, and calls send_file. In this place it is important to use the absolute path.
 #  rails  ( app/controllers/downloads_controller.rb) send_file('/mnt/filestorage/kino.avi') 

4. Rails (more precisely Rack) decides what to do with this file. Previously, at this stage, the content of the file was included in the response body. But we changed the settings of the Rails application, and now instead of the contents of the file, the response will be the X-Accel-Redirect header, which Nginx will then process. The response body will be empty. Also, the file path is changed according to the information from the X-Accel-Mapping header.
 #  Rails (config/environments/production.rb) config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' 

 # HTTP  HTTP/1.1 200 OK X-Accel-Redirect: /private_files/kino.avi Content-Type: application/octet-stream Content-length: ... Content-Disposition: attachment; filename="kino.avi"    

5. Nginx processes this header, finds a suitable location, changes the path to the file and gives it to the user.
 #  Nginx location /private_files/ { internal; alias /mnt/filestorage/; } 

 # HTTP  HTTP/1.1 200 OK Content-Type: application/octet-stream Content-Length: ... Content-Disposition: attachment; filename="kino.avi" < /mnt/filestorage/kino.avi> 

6. The user's browser receives the file.

If you use Passenger, then in Nginx configurations, instead of using proxy_set_header use passenger_set_cgi_param

Source: https://habr.com/ru/post/172531/


All Articles