Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can CarrierWave upload to Amazon S3 but serve through CloudFront?

I'm working on a small rails site which allows some users to upload images and others to see them. I started using CarrierWave with S3 as the storage medium and everything worked great but then I wanted to experiment with using CouldFront. I first added a distribution to my S3 bucket and then changed the CarrierWave configuration I was using to this:

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_credentials = {
    :provider               => 'AWS',                                         # required
    :aws_access_key_id      => ENV['S3_ACCESS_KEY_ID'],                       # required
    :aws_secret_access_key  => ENV['S3_SECRET_ACCESS_KEY'],                   # required
    :region                 => 'eu-west-1',
  }
  config.asset_host = 'http://static.my-domain.com/some-folder'
  config.fog_public     = true                                   # optional, defaults to    true
  config.fog_attributes = {'Cache-Control'=>'max-age=315576000'}  # optional, defaults to {}
end

I should mention that http://static.my-domain.com is a CNAME entry pointing to a CloudFront endpoint (some-id.cloudfront.net). The result is that the pictures are shown correctly, URLs look like this: http://static.my-domain.com/some-folder/uploads/gallery_image/attachment/161/large_image.jpg but whenever I try to upload a photo or for that matter get the size of the uploaded attachment I get the following exception:

Excon::Errors::MovedPermanently: Expected(200) <=> Actual(301 Moved Permanently)
  response => #<Excon::Response:0x007f61fc3d1548 @data={:body=>"", 
  :headers=>{"x-amz-request-id"=>"some-id", "x-amz-id-2"=>"some-id", 
  "Content-Type"=>"application/xml", "Transfer-Encoding"=>"chunked", 
  "Date"=>"Mon, 31 Mar 2014 21:16:45 GMT", "Connection"=>"close", "Server"=>"AmazonS3"}, 
  :status=>301, :remote_ip=>"some-ip"}, @body="", @headers={"x-amz-request-id"=>"some-id", 
  "x-amz-id-2"=>"some-id", "Content-Type"=>"application/xml", 
  "Transfer-Encoding"=>"chunked", "Date"=>"Mon, 31 Mar 2014 21:16:45 GMT", 
  "Connection"=>"close", "Server"=>"AmazonS3"}, @status=301, @remote_ip="some-ip"

Just to add some more info, I tried the following:

  • removing the region entry
  • using the CloudFront URL directly instead of the CNAME
  • specifying the Amazon endpoint (https://s3-eu-west1.amazonaws.com)

but all of them had no effect.

Is there something I'm missing or is it that CarrierWave does not support this at this time?

like image 648
Cristian Badila Avatar asked Mar 31 '14 22:03

Cristian Badila


2 Answers

The answer to the question is YES. The reason why it didn't work with my configuration is that I was missing the fog_directory entry. When I added my asset_host, I removed fog_directory since the CDN urls being generated where malformed. I later found out that this was due to having fog_public set to false. After getting the proper CDN urls, I forgot to add fog_directory back since I could see my images and thought everything was fine. Anyway the correct configuration is:

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_credentials = {
    :provider               => 'AWS',                                         # required
    :aws_access_key_id      => ENV['S3_ACCESS_KEY_ID'],                       # required
    :aws_secret_access_key  => ENV['S3_SECRET_ACCESS_KEY'],                   # required
    :region                 => 'eu-west-1'
  }

  config.fog_directory  = '-bucket-name-/-some-folder-'
  config.asset_host = 'https://static.my-domain.com/-some-folder-'
  config.fog_public     = true                                   # optional, defaults to true
  config.fog_attributes = {'Cache-Control'=>'max-age=315576000'}  # optional, defaults to {}
end
like image 159
Cristian Badila Avatar answered Oct 20 '22 17:10

Cristian Badila


Try setting :asset_host in your Uploader like so:

class ScreenshotUploader < CarrierWave::Uploader::Base
  storage :fog 

  # Configure uploads to be stored in a public Cloud Files container
  def fog_directory
    'my_public_container'
  end

  # Configure uploads to be delivered over Rackspace CDN
  def asset_host
   "c000000.cdn.rackspacecloud.com"
  end
end

Inspired from https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Store-private-public-uploads-in-different-Cloud-Files-Containers-with-Fog

like image 40
Calin Avatar answered Oct 20 '22 18:10

Calin