Can CarrierWave upload to Amazon S3 but serve through CloudFront? - ruby-on-rails

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?

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

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

Related

amazon s3 variables not working in heroku environment rails

Hello I have included given code
def store_s3(file)
# We create a connection with amazon S3
AWS.config(access_key_id: ENV['S3_ACCESS_KEY'], secret_access_key: ENV['S3_SECRET'])
s3 = AWS::S3.new
bucket = s3.buckets[ENV['S3_BUCKET_LABELS']]
object = bucket.objects[File.basename(file)]
# the file is not the content of the file is the route
# file_data = File.open(file, 'rb')
object.write(file: file)
# save the file and return an url to download it
object.url_for(:read, response_content_type: 'text/csv')
end
this code is working correctly in my local data is stored in amazon but when I had deployed code in heroku server I had made variables on server too.
is there anything which I am missing here please let me know cause of issue.
I don't see region, in your example is S3_Hostname your region?
for myself, region was just like 'us-west-2'.
If you want to setup your s3 with carrierwave and gem fog you can do it like this on config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_directory = 'name for s3 directory'
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => 'your access key',
:aws_secret_access_key => 'your secret key',
:region => 'your region ex: eu-west-2'
}
end

Rails carrierwave link generated different from s3 storage link

I created a rails api but I have a problem with image upload.
I'm using carrierwave , the upload of picture is working but I get a wrong link.
Example :
This is the link I find in the RESTful api :
https://s3.eu-west-2.amazonaws.com/gpsql/uploads/driver/picture/35/imagename.png
But when I check S3 storage I find a different link :
https://s3.eu-west-2.amazonaws.com/gpsql/gpsql/gpsql/uploads/driver/picture/35/imagename.png
This is initializer for s3 carrierwave :
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws' # required
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: '...', # required
aws_secret_access_key: '...', # required
region: 'us-west-2',
path_style: true,
}
config.fog_directory = 'gpsql' # required
config.asset_host = 'https://s3.eu-west-2.amazonaws.com/gpsql'
config.fog_attributes = {'Cache-Control' => "max-age=#{365.day.to_i}"} # optional, defaults to {}
end
In picture uploader :
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
How can I fix the link that is shown in the RESTful api also why there is so much "bucket name" in amazon link why not something straightforward link/bucketname/image.png
For the first link I find in restful api it doesn't work at all I get access denied or key not found for the second one in amazon s3 it works without any problem.
One of the problem is this
config.asset_host = 'https://s3.eu-west-2.amazonaws.com/gpsql'
it should be
config.asset_host = 'https://s3.eu-west-2.amazonaws.com'
Anyway I don't know why it's repeating twice...
So, if you can you should fix it in the configuration and move the folder in S3 to the proper place
If you can't move it I would try to change the store dir to "gpsql/gpsql/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
I'm not sure if that works but that would be my first step

Merge uploaded Amazon S3 images into CloudFront

I started to integrate CloudFront into my exciting Rails App, everything with CloudFront is working fine, except that the old uploaded images can't be accessed.
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
}
config.asset_host = ENV['CLOUDFRONT_ENDPOINT']
config.fog_directory = 'oktob-editor'
config.fog_public = true
config.fog_attributes = {'Cache-Control'=>"max-age=#{365.day.to_i}"}
end
Example of old uploaded image
https://oktob-editor.s3.amazonaws.com/uploads/post/image/127/thumb_Ruby_on_Rails.svg.png
After I integrated CloudFront and set asset_host it becomes
http://ID.cloudfront.net/uploads/post/image/127/thumb_Ruby_on_Rails.svg.png
with
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>D368D2E641BBBB64</RequestId><HostId></HostId></Error>
So is there a way that enable old images to work properly with CloudFront
Seems like changing the Restrict Bucket Access to Yes makes it to work

Carrierwave fog Amazon S3 images not displaying

I have installed carrierwave and fog, have successfully uploaded the images and viewed them the first time, but now it does not show the images anymore.
Here is my config file app/config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'AKIAJKOHTE4WTXCCXAMA', # required
:aws_secret_access_key => 'some secret key here', # required
:region => 'eu-east-1', # optional, defaults to 'us-east-1'
:host => 'https://s3.amazonaws.com', # optional, defaults to nil
:endpoint => 'https://s3.amazonaws.com:8080' # optional, defaults to nil
}
config.fog_directory = 'createmysite.co.za' # required
config.fog_public = false # optional, defaults to true
#config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
This is what the url looks like of the image that is supposed to display
<img alt="Normal_selection_003" src="https://createmysite.co.za.s3.amazonaws.com/uploads/portfolio/image/3/normal_Selection_003.png?AWSAccessKeyId=AKIAJKOHTE4WTXCCXAMA&Signature=8PLq8WCkfrkthmfVGfXX9K6s5fc%3D&Expires=1354859553">
when I open the image url this is the output from amazon
https://createmysite.co.za.s3.amazonaws.com/uploads/portfolio/image/3/normal_Selection_003.png?AWSAccessKeyId=AKIAJKOHTE4WTXCCXAMA&Signature=8PLq8WCkfrkthmfVGfXX9K6s5fc%3D&Expires=1354859553
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>3F179B7CE417BC12</RequestId>
<HostId>
zgh46a+G7UDdpIHEEIT0C/rmijShOKAzhPSbLpEeVgUre1iDc9f7TSOwaJdQpR65
</HostId>
</Error>
Update
new config file (added fog url expiry) app/config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'AKIAJKOHTE4WTXCCXAMA', # required
:aws_secret_access_key => 'chuck norris', # required
}
config.fog_directory = 'createmysite.co.za' # required
config.fog_public = false # optional, defaults to true
config.fog_authenticated_url_expiration = 600 # (in seconds) => 10 minutes
end
works like a charm!
You've set config.fog_public to false and are using Amazon S3 for storage. URLs for private files through S3 are temporary (they're signed and have an expiry). Specifically, the URL posted in your question has an Expires=1354859553 parameter.
1354859553 is Fri, 07 Dec 2012 05:52:33 GMT, which is in the past from the current time, so the link has effectively expired, which is why you're getting the Access Denied error.
You can adjust the expiry out further (the default is 600 seconds) by setting
config.fog_authenticated_url_expiration = ... # some integer here
If you want non-expiring links either
set config.fog_public to true
have your application act as a middle man, serving the files up through send_file. Here is at least one question on SO covering this

carrierwave, Excon::Errors::MovedPermanently in RegistrationsController#update error

ive been trying to get carrierwave to work with amazon s3. instead of
storage :s3
i have
storage :fog
changing it to storage :s3 gives an immediate error
https://stackoverflow.com/questions/10629827/carrierwave-cant-convert-nil-into-string-typeerror-when-using-s3
so i changed it to storage :fog like the rdoc below says.
http://rubydoc.info/gems/carrierwave/frames
however when i try to upload an image, i get this crazy error. im using the devise gem as well.
my full stack trace is
Excon::Errors::MovedPermanently in RegistrationsController#update
Excon::Errors::MovedPermanently (Expected(200) <=> Actual(301 Moved Permanently)
request => {:connect_timeout=>60, :headers=>{"Content-Length"=>95472, "Content-Type"=>"image/jpeg", "x-amz-acl"=>"private", "Cache-Control"=>"max-age=315576000", "Date"=>"Thu, 17 May 2012 05:28:55 +0000", "Authorization"=>"AWS AKIAIN6SC3YSGBSUKV4Q:kZOG9mG01jYn48ImFMYbgxAAQRk=", "Host"=>"user.a.777.s3-eu-west-1.amazonaws.com:443"}, :instrumentor_name=>"excon", :mock=>false, :read_timeout=>60, :retry_limit=>4, :ssl_ca_file=>"/Users/sasha/.rvm/gems/ruby-1.9.3-p125/gems/excon-0.13.4/data/cacert.pem", :ssl_verify_peer=>true, :write_timeout=>60, :host=>"user.a.777.s3-eu-west-1.amazonaws.com", :path=>"/uploads%2Fuser%2Fimage%2F59%2Fidea.jpg", :port=>"443", :query=>nil, :scheme=>"https", :body=>#<File:/Users/sasha/Desktop/rails_projects/blue_eyes/public/uploads/tmp/20120516-2228-19160-9893/idea.jpg>, :expects=>200, :idempotent=>true, :method=>"PUT"}
response => #<Excon::Response:0x007fd72a146820 #body="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>PermanentRedirect</Code><Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message><RequestId>F5F5AF888E837622</RequestId><Bucket>user.a.777</Bucket><HostId>IShK3GIthzCQysLOKXnR+ijJiHmMuUtXBOpFxQM4uCvJgkEHfmFn43LL4oWmpT82</HostId><Endpoint>s3.amazonaws.com</Endpoint></Error>", #headers={"x-amz-request-id"=>"F5F5AF888E837622", "x-amz-id-2"=>"IShK3GIthzCQysLOKXnR+ijJiHmMuUtXBOpFxQM4uCvJgkEHfmFn43LL4oWmpT82", "Content-Type"=>"application/xml", "Transfer-Encoding"=>"chunked", "Date"=>"Thu, 17 May 2012 05:29:00 GMT", "Connection"=>"close", "Server"=>"AmazonS3"}, #status=301>):
app/controllers/registrations_controller.rb:30:in `update'
i dont know what that even means.
in my initializers/carrierwave.rb i have..
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'somekey', # required
:aws_secret_access_key => 'secretkey', # required
:region => 'eu-west-1' # optional, defaults to 'us-east-1'
}
config.fog_directory = 'bucket.name' # required
#config.fog_host = 'https://s3.amazonaws.com' # optional, defaults to nil
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
and my uploader file has
#storage :s3
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
my gem file has
gem 'carrierwave'
gem 'thin'
gem 'fog'
when i boot my server, instead of webrick, it uses thin in development as well.
are my configurations wrong?
help would be much appreciated!
ive been super stuck on this carrierwave/s3 issue
I ran into this the earlier today and it was a problem with the region. Just take it out and let it be set by the default.
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'somekey', # required
:aws_secret_access_key => 'secretkey' # required
}
config.fog_directory = 'bucket.name' # required
#config.fog_host = 'https://s3.amazonaws.com' # optional, defaults to nil
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
For me worked this configuration
config.fog_directory = 'bucket_name'
config.fog_host = 'https://s3-eu-west-1.amazonaws.com/bucket_name'
I had the same problem.
Following the 3 steps below worked for me.
1.Change the default region when creating a bucket
2.Edit my carrierwave.rb file(as shown below)
initializers/carrierwave.rb:
if Rails.env.production?
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => ENV['S3_ACCESS_KEY'],
:aws_secret_access_key => ENV['S3_SECRET_KEY'],
:region => ENV['S3_REGION']
}
config.fog_directory = ENV['S3_BUCKET']
end
end
3.Configure heroku in the command line as in: heroku config:set S3_REGION='your region'
Just like #Jason Bynum said, do not specify the region and let it default.
If you still fail, don't worry, At this time, heroku will give hint to you like your region specified is wrong and should be xxx
And you know how to fill the region right now :)
The followings work for me:
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: ENV['S3_KEY'], # required
aws_secret_access_key: ENV['S3_SECRET'], # required
region: 'ap-southeast-1', # optional, defaults to 'us-east-1'
}
config.fog_directory = 'your_bucket_name' # required
config.fog_public = false # optional, defaults to true
config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {}
end
Gemfile:
gem 'carrierwave', '0.10.0'
gem 'fog', '1.36.0'

Resources