Lưu trữ hình ảnh tới remote server trong Ruby on Rails với vsftpd

vsftpd.png

Khi phát triển một website chắc hẳn chúng ta quan tâm rất nhiều tới vấn đề tải lên và lưu trữ hình ảnh của người dùng.

Bài viết này mình trình bày một số cách thông thường để giải quyết vấn đề này. Trong qúa trình mình làm projects đã gặp phải một vài khúc mắc, do vậy mình ghi lại bài viết để tiện theo dõi cho lần sau và cũng giúp cho người mới bắt đầu như mình tiếp cận dễ hơn và rút ngắn thời gian tìm hiểu.

Để tài hình ảnh lên server, Rails cung cấp một vài thư viện cho chúng ta như:

Carrierwave Gem

Paperclip Gem

Tùy từng sở thích mỗi người mà lựa chọn gem riêng cho phần này. Mình sử dụng quen thuộc gem carrierwave. Do vậy bài viết này mình sử dụng nó.

Đa số ứng dụng website đều lưu trữ hình ảnh, database và deploy code ở các server riêng để đảm bảo dễ quản lý, tăng cường bảo mật hay tăng hiệu suất hoạt động hơn cũng như giảm thiểu rủi ro hơn khi dùng chung server.

Về phần kết nối vào database server mình đã có viết một bài rồi, mọi người có thể tham khảo ở link sau Kết nối với Database trong Rails

Bài này mình trình bày về phần tải hình ảnh lên server.

Upload lên server lưu trữ hình ảnh riêng

Để upload hình ảnh cũng như tệp tin khác lên remote server mình sử dụng FTP. Trong ubuntu có gói phần mềm là vsftpd.

Chuẩn bị server để lưu trữ hình ảnh

Tạo người dùng mới (không nên sử dụng root), mình ví dụ tạo người dùng tên là demo.

$ ssh <remote_server>
root:~# adduser demo
password for `demo`
...

Tạo thư mục cho upload hình ảnh lên và gán quyền cho user.

:~# cd /home/demo/
:~# mkdir public_html/uploads -p
:~# chmod 755 public_html -R
:~# chown demo:demo public_html -R

Cài đặt và cấu hình vsftpd server trên ubuntu.

ssh <remote server>
sudo apt-get install vsftpd

Mở file cấu hình /etc/vsftpd.conf và sửa một số dòng thông tin sau:

Việc đầu tiên cần làm là tắt quyền truy cập của anonymous user bằng cách thay đổi anonymous_enable từ yes sang no

anonymous_enable=NO

Thứ 2 cần cấp quyền tạo và ghi thư mục

bỏ comment trước local_enable và chuyển giá trị từ NO sang YES

local_enable=YES

write_enable=YES

Với cấu hình như trên thì khi demo user đã có thể upload được hình ảnh cũng như tệp tin lên server rồi.

Tuy nhiên khi upload lên thì hình ảnh sẽ chịu tác động tổng hợp từ quyền cơ bản (777) với thư mục và (666) đối vơi file và một gía trị cấu hình local umask của server ftp.

Gía trị mặc định local_umask của vsftpd077.

Chúng ta cùng tìm hiểu về umask.

The user file-creation mode mask (umask) - đó là xác định quyền của tệp tin khi mới được tạo ra.

Quyền cơ bản của file là 0666 (hay 666) và thư mục là 0777 (hay 777).

Như vậy file và thư mục khi mới tạo ra sẽ chịu tác động tổng hợp từ base permission trên và gía trị local_umask.

Vậy cách tính quyền file và thư mục khi mới tạo ra từ 2 quyền kia như thế nào?

`quyền mới file or folder` = `base permisstion` - `local_umask`

Ví dụ khi ta set local_umask = 002 thì:

File được tạo ra sẽ có quyền là: 666 - 002 = 664.

Folder được tạo ra có quyền là: 777 - 002 = 775.

Với gía trị mặc định local_umask của vsftpd077, vậy file được tạo ra có quyền là 600. Do vậy khi upload hình ảnh lên server người dùng sẽ không thể xem được.

Do vậy chúng ta nên đặt local_umask002 hoặc 022.

Tìm kiếm tới dòng sau trong file cấu hình vsftpd và sửa lại thành như sau:

local_umask = 022

Khởi động lại vsftpd server.

service vsftpd restart

Cấu hình rails app của bạn

Chúng ta sử dụng gem sau để upload lên server đã cấu hình ở phía trên dùng ftp server.

https://github.com/luan/carrierwave-ftp

Thêm dòng sau vào Gemfile

gem 'carrierwave-ftp', :require => 'carrierwave/storage/ftp/all' # both FTP/SFTP
gem 'mini_magick',             '3.8.0'
gem 'carrierwave',             '0.10.0'

Chạy bundle install --without production để cài đặt.

Tạo file config/initializes/carrierwave.rb với thông tin như sau:

CarrierWave.configure do |config|
  config.ftp_host = ENV['ftp_host']
  config.ftp_user = ENV['ftp_user']
  config.ftp_passwd = ENV['ftp_passwd']
  config.ftp_folder = "/public_html"
  config.ftp_url = ENV['ftp_url']
  config.ftp_passive = true
end

Chú ý cần export các biến environments ở trên heroku.

Tiếp theo là cấu hình carrierwave

Ở đây mình sử dụng carrierwave và tạo một uploader tên là pictures_uploader.rb có nội dung như sau:

class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  if Rails.env.production?
    storage :ftp
  else
    storage :file
  end

  version :medium do
    process resize_to_fill: [480, 360]
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def extension_white_list
    %w(jpg jpeg gif png)
  end
end

Vậy là đã xong cấu hình cho phép user upload hình ảnh lên server remote rồi. 😄


All Rights Reserved