使用CDN,在s3中使用载波+雾,在cloudfront中使用rails 3.1

时间:2023-01-08 23:03:00

I'm using fog with carrierwave in my website. But the images load very very slowly.

我在我的网站上使用雾和载波。但是图像加载很慢。

Then I want to speed up loading of images with a CDN.

然后我想用CDN加快图像加载速度。

I have followed this tutorial for create the CDN for images:

我已经按照本教程为图像创建CDN:

http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25

http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25

I have now my distribution deployed for images but I don't know how works fine the cdn. I have in initializers/fog.rb the next configuration:

我现在已经为图像部署了分布,但我不知道如何对cdn进行优化。我有在初始化/雾。rb接下来的配置:

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',
    :aws_access_key_id      => 'key',
    :aws_secret_access_key  => 'key',
    :region                 => 'eu-west-1'
  }
  config.fog_host = "http://da33ii2cvf53u.cloudfront.net" #config.asset_host instead of config.fog_host for new fog gem versions
  config.fog_directory  = 'pin-pro'
  config.fog_public     = false
  #config.fog_attributes = {'Cache-Control' => 'max-age=315576000'} 
end 

I dont know if this is correct, but in my local machine it does not works fine for me. I see the image location, is the same route as before:

我不知道这是否正确,但在我的本地机器上,它对我来说并不好。我看到图片的位置,和之前的路线是一样的:

https://s3-eu-west-1.amazonaws.com/pin-pro/uploads/pins/medium_610cafbe-5d43-4223-ab0e-daa4990863c4.jpg?AWSAccessKeyId=AKIAIDX34WHYKB3ZKFVA&Signature=RwQriNpiRXaTxyfYVvYjsvclUa8%3D&Expires=1333203059

How can I add a CDN to fog file in carrierwave with s3 and cloudfront?

如何在带有s3和cloudfront的carrierwave文件中向fog文件添加CDN ?

4 个解决方案

#1


8  

It looks like you haven't added the line below to your config. You will need to replace the sample address below with your cloudfront address from Amazon.

看起来您还没有将下面的行添加到配置中。您需要将下面的示例地址替换为来自Amazon的cloudfront地址。

From the github README: https://github.com/jnicklas/carrierwave

来自github README: https://github.com/jnicklas/carrierwave

"You can optionally include your CDN host name in the configuration. This is highly recommended, as without it every request requires a lookup of this information"

您可以选择在配置中包含您的CDN主机名。强烈建议这样做,因为没有它,每个请求都需要查找此信息”

config.asset_host = "http://c000000.cdn.rackspacecloud.com"

配置。asset_host = " http://c000000.cdn.rackspacecloud.com "

#2


10  

CarrierWave won't work when you set config.fog_public = false and point config.asset_host to a CloudFront distribution. This has been documented multiple times:

当你设置配置时,CarrierWave不会工作。fog_public = false和point config。asset_host到CloudFront分布。这已经被记录了很多次:

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

In a recent project I was happy using CarrierWave to handle uploads to S3, but wanted it to return a signed CloudFront URL when using Model.attribute_url. I came up with the following (admittedly ugly) workaround that I hope others can benefit from or improve upon:

在最近的一个项目中,我很高兴使用CarrierWave处理S3的上传,但是希望它在使用Model.attribute_url时返回一个签名的CloudFront URL。我提出了以下(公认的丑陋)解决方案,希望其他人能从中受益或改进:

Add the 'cloudfront-signer' gem to your project and configure it per the instructions. Then add the following override of /lib/carrierwave/uploader/url.rb in a new file in config/initializers (note the multiple insertions of AWS::CF::Signer.sign_url):

将“cloudfront-signer”gem添加到项目中,并根据说明对其进行配置。然后添加以下/lib/carrierwave/uploader/url覆盖。配置/初始化器中的新文件中的rb(注意AWS:::CF::Signer.sign_url的多重插入):

module CarrierWave
      module Uploader
        module Url
          extend ActiveSupport::Concern
          include CarrierWave::Uploader::Configuration
          include CarrierWave::Utilities::Uri

          ##
          # === Parameters
          #
          # [Hash] optional, the query params (only AWS)
          #
          # === Returns
          #
          # [String] the location where this file is accessible via a url
          #
          def url(options = {})
            if file.respond_to?(:url) and not file.url.blank?
              file.method(:url).arity == 0 ? AWS::CF::Signer.sign_url(file.url) : AWS::CF::Signer.sign_url(file.url(options))
            elsif file.respond_to?(:path)
              path = encode_path(file.path.gsub(File.expand_path(root), ''))

              if host = asset_host
                if host.respond_to? :call
                  AWS::CF::Signer.sign_url("#{host.call(file)}#{path}")
                else
                  AWS::CF::Signer.sign_url("#{host}#{path}")
                end
              else
                AWS::CF::Signer.sign_url((base_path || "") + path)
              end
            end
          end

        end # Url
     end # Uploader
end # CarrierWave

Then override /lib/carrierwave/storage/fog.rb by adding the following to the bottom of the same file:

然后覆盖/lib/carrierwave /存储/雾。通过在同一文件的底部添加以下内容:

require "fog"

module CarrierWave
  module Storage
    class Fog < Abstract
       class File
          include CarrierWave::Utilities::Uri
          def url
             # Delete 'if statement' related to fog_public
             public_url
          end
       end
    end
  end
end

Lastly, in config/initializers/carrierwave.rb:

最后,在config /初始化/ carrierwave.rb:

config.asset_host = "http://d12345678.cloudfront.net"

配置。asset_host = " http://d12345678.cloudfront.net "

config.fog_public = false

配置。fog_public = false

That's it. You can now use Model.attribute_url and it will return a signed CloudFront URL to a private file uploaded by CarrierWave to your S3 bucket.

就是这样。现在可以使用Model了。attribute_url,它会将签名的CloudFront URL返回给CarrierWave上传到S3 bucket的一个私有文件。

#3


6  

seems that amazon cdn doesn't work with config.fog_public = false, so private files are accessible only from s3, not from cdn

看起来amazon cdn不支持配置。fog_public = false,因此只能从s3访问私有文件,而不能从cdn

#4


1  

After some searching and struggling with this for a long time I found a page that says that CarrierWave doesn't support CloudFront signed urls. CloudFront signed urls are different than S3 signed urls, which caused me some confusion. Once I figured that out, it was a lot easier to know what to do.

经过长时间的搜索和努力,我发现一个页面说CarrierWave不支持CloudFront签名的url。CloudFront签名的url与S3签名的url不同,这让我有些困惑。一旦我明白了这一点,就更容易知道该怎么做了。

If you configure CarrierWave with config.fog_public = false then it will automatically begin signing S3 urls, but it can't be configured to work with Fog and CloudFront private content in the version of CarrierWave I'm using (1.0.0). I even tried using the carrierwave-aws gem and that didn't help either.

如果您使用config配置CarrierWave。fog_public = false,然后它将自动开始签名S3 url,但是不能将其配置为在我正在使用的CarrierWave版本中使用Fog和CloudFront私有内容(1.0.0)。我甚至试过使用了carrierwave-aws gem,但这也无济于事。

So what would happen is that CarrierWave would sign the URL and the host would look something like this:

所以会发生的是CarrierWave会在URL上签名主机会是这样的

https://my_bucket_name.s3-us-west-2.amazonaws.com/uploads/...?signature...

That points directly to the S3 bucket, but I needed it to point to CloudFront. I needed the host to look like this:

这直接指向S3桶,但我需要它指向CloudFront。我需要主持人看起来像这样:

https://s3.cloudfront_domain_name.com/uploads/...

And what would happen if I set config.asset_host equal to my CloudFront location is I'd get this, (with double slashes before "uploads"):

如果我设置config会发生什么呢?asset_host等于我的CloudFront位置,我得到这个(在“上传”之前有两个斜杠):

https://s3.cloudfront_domain_name.com//uploads/...

That, too, made it clear CarrierWave wasn't yet designed to be used with CloudFront. Hopefully they'll improve it. This was my work-around. It's ugly, but it worked to get done what I needed without needing to modify CarrierWave itself, as I hope CarrierWave will at some point add support for CloudFront.

这也清楚地表明,CarrierWave还没有设计成用于CloudFront。希望他们会改善的。这是我的变通方法。它很难看,但是它成功地完成了我需要的工作,而不需要修改CarrierWave本身,因为我希望CarrierWave会在某个时候增加对CloudFront的支持。

  1. First I did a regex find/replace on my url and removed the S3 host portion and put on my CloudFront host portion. cf_url = s3_url.gsub("my_bucket_name.s3-us-west-2.amazonaws.com", "s3.cloudfront_domain_name.com")
  2. 首先,我在url上做了一个regex查找/替换,并删除了S3主机部分,并将其放在CloudFront主机部分。cf_url = s3_url.gsub(“my_bucket_name.s3 -我们-西方- 2. - amazonaws.com "," s3.cloudfront_domain_name.com ")
  3. Next I did another regex find/replace to remove the S3 signed url at the end of the string: non_signed_cf_url = cf_url.gsub(/\?.+/, '') This is because the signature will be incorrect because it was using the API for S3 and not for CloudFront for signing the URL.
  4. 接下来,我做了另一个regex查找/替换,以删除字符串末尾的S3签名url: non_signed_cf_url = cf_url.gsub(/\?)这是因为签名是不正确的,因为它使用的是S3的API,而不是CloudFront的URL签名。
  5. Now I re-sign the URL myself, using the cloudfront-signer gem: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)
  6. 现在,我使用cloudfront-signer gem: signed_cf_url = Aws::::CF: Signer重新签名URL。sign_url(non_signed_cf_url:= > 1. day.from_now)到期

There are a few other things you need to be aware of when serving private content on CloudFront:

在CloudFront上服务私有内容时,还需要注意以下几点:

  • In the Cache Behavior Settings for your path pattern (not necessarily the default one), set: "Restrict Viewer Access (Use Signed URLs or Signed Cookies)" to "Yes"
  • 在您的路径模式(不一定是默认的)的缓存行为设置中,设置:“限制查看器访问(使用已签名的url或签名的cookie)”到“Yes”。
  • Set "Trusted Signers" to "self"
  • 将“可信签名者”设置为“self”
  • Set "Query String Forwarding and Caching" to "Forward all, cache based on all" if you want to use other query strings more than the CloudFront signature in your url, such as response-content-disposition and response-content-type (I was able to get these to work successfully, but they have to be url_encoded properly.)
  • 如果您希望使用比url中的CloudFront签名更多的查询字符串,例如响应-内容-配置和响应-内容-类型,则将“查询字符串转发和缓存”设置为“转发所有的、基于所有的”(我能够使它们成功工作,但它们必须正确地使用url_encoded)。
  • In your CloudFront Origin Settings, set your access-identity and set "Grant Read Permissions on Bucket" to "Yes, Update Bucket Policy"
  • 在CloudFront源设置中,设置访问标识并将“授予Bucket的读权限”设置为“Yes, Update Bucket策略”
  • In your General Distribution Settings, make sure "Distribution State" is "Enabled" and that you've added a CNAME to "Alternate Domain Names (CNAMEs)" if you're using one.
  • 在您的通用分布设置中,确保“分布状态”是“启用”的,并且如果您正在使用“备用域名称(CNAME)”,那么您已经添加了一个CNAME。
  • If using a CNAME, make sure your DNS is correctly configured to point it to your CloudFront distribution's name.
  • 如果使用CNAME,请确保正确配置了DNS,将其指向CloudFront分发版的名称。
  • Lastly, once you set the configurations there is a long wait while AWS updates the distribution, so you won't see your changes happen right away. It may seem like your app/website is still broken until the changes propagate through CloudFront. This can make configuring it difficult because if you get it wrong you have to wait a long time before you can see your changes take effect and you may not be sure what happened. But with these settings I was able to get it working for me.
  • 最后,一旦您设置了配置,就需要等待很长时间,而AWS则更新发行版,因此您不会立即看到更改发生。在更改通过CloudFront传播之前,您的应用程序/网站似乎仍然处于崩溃状态。这可能会使配置变得困难,因为如果您出错,您必须等待很长时间才能看到更改生效,并且您可能不确定发生了什么。但是有了这些设置,我就能让它为我工作。
  • You can also create more than one caching path pattern so that some content is private and requires a CloudFront signed url, and other content isn't. For example, I set a path pattern of *.mp4 that requires a signature for all mp4 files and placed that above the default behavior. And then I have the default cache behavior set to NOT require signed urls, which allows all other files - such as images - to be publicly accessible through the CloudFront distribution.
  • 您还可以创建多个缓存路径模式,以便某些内容是私有的,需要一个CloudFront签名的url,而其他内容不是。例如,我设置了*的路径模式。mp4要求所有mp4文件都有一个签名,并将其置于默认行为之上。然后,我设置了默认的缓存行为,不需要签名url,这允许通过CloudFront发行版公开访问所有其他文件(如图像)。

#1


8  

It looks like you haven't added the line below to your config. You will need to replace the sample address below with your cloudfront address from Amazon.

看起来您还没有将下面的行添加到配置中。您需要将下面的示例地址替换为来自Amazon的cloudfront地址。

From the github README: https://github.com/jnicklas/carrierwave

来自github README: https://github.com/jnicklas/carrierwave

"You can optionally include your CDN host name in the configuration. This is highly recommended, as without it every request requires a lookup of this information"

您可以选择在配置中包含您的CDN主机名。强烈建议这样做,因为没有它,每个请求都需要查找此信息”

config.asset_host = "http://c000000.cdn.rackspacecloud.com"

配置。asset_host = " http://c000000.cdn.rackspacecloud.com "

#2


10  

CarrierWave won't work when you set config.fog_public = false and point config.asset_host to a CloudFront distribution. This has been documented multiple times:

当你设置配置时,CarrierWave不会工作。fog_public = false和point config。asset_host到CloudFront分布。这已经被记录了很多次:

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

In a recent project I was happy using CarrierWave to handle uploads to S3, but wanted it to return a signed CloudFront URL when using Model.attribute_url. I came up with the following (admittedly ugly) workaround that I hope others can benefit from or improve upon:

在最近的一个项目中,我很高兴使用CarrierWave处理S3的上传,但是希望它在使用Model.attribute_url时返回一个签名的CloudFront URL。我提出了以下(公认的丑陋)解决方案,希望其他人能从中受益或改进:

Add the 'cloudfront-signer' gem to your project and configure it per the instructions. Then add the following override of /lib/carrierwave/uploader/url.rb in a new file in config/initializers (note the multiple insertions of AWS::CF::Signer.sign_url):

将“cloudfront-signer”gem添加到项目中,并根据说明对其进行配置。然后添加以下/lib/carrierwave/uploader/url覆盖。配置/初始化器中的新文件中的rb(注意AWS:::CF::Signer.sign_url的多重插入):

module CarrierWave
      module Uploader
        module Url
          extend ActiveSupport::Concern
          include CarrierWave::Uploader::Configuration
          include CarrierWave::Utilities::Uri

          ##
          # === Parameters
          #
          # [Hash] optional, the query params (only AWS)
          #
          # === Returns
          #
          # [String] the location where this file is accessible via a url
          #
          def url(options = {})
            if file.respond_to?(:url) and not file.url.blank?
              file.method(:url).arity == 0 ? AWS::CF::Signer.sign_url(file.url) : AWS::CF::Signer.sign_url(file.url(options))
            elsif file.respond_to?(:path)
              path = encode_path(file.path.gsub(File.expand_path(root), ''))

              if host = asset_host
                if host.respond_to? :call
                  AWS::CF::Signer.sign_url("#{host.call(file)}#{path}")
                else
                  AWS::CF::Signer.sign_url("#{host}#{path}")
                end
              else
                AWS::CF::Signer.sign_url((base_path || "") + path)
              end
            end
          end

        end # Url
     end # Uploader
end # CarrierWave

Then override /lib/carrierwave/storage/fog.rb by adding the following to the bottom of the same file:

然后覆盖/lib/carrierwave /存储/雾。通过在同一文件的底部添加以下内容:

require "fog"

module CarrierWave
  module Storage
    class Fog < Abstract
       class File
          include CarrierWave::Utilities::Uri
          def url
             # Delete 'if statement' related to fog_public
             public_url
          end
       end
    end
  end
end

Lastly, in config/initializers/carrierwave.rb:

最后,在config /初始化/ carrierwave.rb:

config.asset_host = "http://d12345678.cloudfront.net"

配置。asset_host = " http://d12345678.cloudfront.net "

config.fog_public = false

配置。fog_public = false

That's it. You can now use Model.attribute_url and it will return a signed CloudFront URL to a private file uploaded by CarrierWave to your S3 bucket.

就是这样。现在可以使用Model了。attribute_url,它会将签名的CloudFront URL返回给CarrierWave上传到S3 bucket的一个私有文件。

#3


6  

seems that amazon cdn doesn't work with config.fog_public = false, so private files are accessible only from s3, not from cdn

看起来amazon cdn不支持配置。fog_public = false,因此只能从s3访问私有文件,而不能从cdn

#4


1  

After some searching and struggling with this for a long time I found a page that says that CarrierWave doesn't support CloudFront signed urls. CloudFront signed urls are different than S3 signed urls, which caused me some confusion. Once I figured that out, it was a lot easier to know what to do.

经过长时间的搜索和努力,我发现一个页面说CarrierWave不支持CloudFront签名的url。CloudFront签名的url与S3签名的url不同,这让我有些困惑。一旦我明白了这一点,就更容易知道该怎么做了。

If you configure CarrierWave with config.fog_public = false then it will automatically begin signing S3 urls, but it can't be configured to work with Fog and CloudFront private content in the version of CarrierWave I'm using (1.0.0). I even tried using the carrierwave-aws gem and that didn't help either.

如果您使用config配置CarrierWave。fog_public = false,然后它将自动开始签名S3 url,但是不能将其配置为在我正在使用的CarrierWave版本中使用Fog和CloudFront私有内容(1.0.0)。我甚至试过使用了carrierwave-aws gem,但这也无济于事。

So what would happen is that CarrierWave would sign the URL and the host would look something like this:

所以会发生的是CarrierWave会在URL上签名主机会是这样的

https://my_bucket_name.s3-us-west-2.amazonaws.com/uploads/...?signature...

That points directly to the S3 bucket, but I needed it to point to CloudFront. I needed the host to look like this:

这直接指向S3桶,但我需要它指向CloudFront。我需要主持人看起来像这样:

https://s3.cloudfront_domain_name.com/uploads/...

And what would happen if I set config.asset_host equal to my CloudFront location is I'd get this, (with double slashes before "uploads"):

如果我设置config会发生什么呢?asset_host等于我的CloudFront位置,我得到这个(在“上传”之前有两个斜杠):

https://s3.cloudfront_domain_name.com//uploads/...

That, too, made it clear CarrierWave wasn't yet designed to be used with CloudFront. Hopefully they'll improve it. This was my work-around. It's ugly, but it worked to get done what I needed without needing to modify CarrierWave itself, as I hope CarrierWave will at some point add support for CloudFront.

这也清楚地表明,CarrierWave还没有设计成用于CloudFront。希望他们会改善的。这是我的变通方法。它很难看,但是它成功地完成了我需要的工作,而不需要修改CarrierWave本身,因为我希望CarrierWave会在某个时候增加对CloudFront的支持。

  1. First I did a regex find/replace on my url and removed the S3 host portion and put on my CloudFront host portion. cf_url = s3_url.gsub("my_bucket_name.s3-us-west-2.amazonaws.com", "s3.cloudfront_domain_name.com")
  2. 首先,我在url上做了一个regex查找/替换,并删除了S3主机部分,并将其放在CloudFront主机部分。cf_url = s3_url.gsub(“my_bucket_name.s3 -我们-西方- 2. - amazonaws.com "," s3.cloudfront_domain_name.com ")
  3. Next I did another regex find/replace to remove the S3 signed url at the end of the string: non_signed_cf_url = cf_url.gsub(/\?.+/, '') This is because the signature will be incorrect because it was using the API for S3 and not for CloudFront for signing the URL.
  4. 接下来,我做了另一个regex查找/替换,以删除字符串末尾的S3签名url: non_signed_cf_url = cf_url.gsub(/\?)这是因为签名是不正确的,因为它使用的是S3的API,而不是CloudFront的URL签名。
  5. Now I re-sign the URL myself, using the cloudfront-signer gem: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)
  6. 现在,我使用cloudfront-signer gem: signed_cf_url = Aws::::CF: Signer重新签名URL。sign_url(non_signed_cf_url:= > 1. day.from_now)到期

There are a few other things you need to be aware of when serving private content on CloudFront:

在CloudFront上服务私有内容时,还需要注意以下几点:

  • In the Cache Behavior Settings for your path pattern (not necessarily the default one), set: "Restrict Viewer Access (Use Signed URLs or Signed Cookies)" to "Yes"
  • 在您的路径模式(不一定是默认的)的缓存行为设置中,设置:“限制查看器访问(使用已签名的url或签名的cookie)”到“Yes”。
  • Set "Trusted Signers" to "self"
  • 将“可信签名者”设置为“self”
  • Set "Query String Forwarding and Caching" to "Forward all, cache based on all" if you want to use other query strings more than the CloudFront signature in your url, such as response-content-disposition and response-content-type (I was able to get these to work successfully, but they have to be url_encoded properly.)
  • 如果您希望使用比url中的CloudFront签名更多的查询字符串,例如响应-内容-配置和响应-内容-类型,则将“查询字符串转发和缓存”设置为“转发所有的、基于所有的”(我能够使它们成功工作,但它们必须正确地使用url_encoded)。
  • In your CloudFront Origin Settings, set your access-identity and set "Grant Read Permissions on Bucket" to "Yes, Update Bucket Policy"
  • 在CloudFront源设置中,设置访问标识并将“授予Bucket的读权限”设置为“Yes, Update Bucket策略”
  • In your General Distribution Settings, make sure "Distribution State" is "Enabled" and that you've added a CNAME to "Alternate Domain Names (CNAMEs)" if you're using one.
  • 在您的通用分布设置中,确保“分布状态”是“启用”的,并且如果您正在使用“备用域名称(CNAME)”,那么您已经添加了一个CNAME。
  • If using a CNAME, make sure your DNS is correctly configured to point it to your CloudFront distribution's name.
  • 如果使用CNAME,请确保正确配置了DNS,将其指向CloudFront分发版的名称。
  • Lastly, once you set the configurations there is a long wait while AWS updates the distribution, so you won't see your changes happen right away. It may seem like your app/website is still broken until the changes propagate through CloudFront. This can make configuring it difficult because if you get it wrong you have to wait a long time before you can see your changes take effect and you may not be sure what happened. But with these settings I was able to get it working for me.
  • 最后,一旦您设置了配置,就需要等待很长时间,而AWS则更新发行版,因此您不会立即看到更改发生。在更改通过CloudFront传播之前,您的应用程序/网站似乎仍然处于崩溃状态。这可能会使配置变得困难,因为如果您出错,您必须等待很长时间才能看到更改生效,并且您可能不确定发生了什么。但是有了这些设置,我就能让它为我工作。
  • You can also create more than one caching path pattern so that some content is private and requires a CloudFront signed url, and other content isn't. For example, I set a path pattern of *.mp4 that requires a signature for all mp4 files and placed that above the default behavior. And then I have the default cache behavior set to NOT require signed urls, which allows all other files - such as images - to be publicly accessible through the CloudFront distribution.
  • 您还可以创建多个缓存路径模式,以便某些内容是私有的,需要一个CloudFront签名的url,而其他内容不是。例如,我设置了*的路径模式。mp4要求所有mp4文件都有一个签名,并将其置于默认行为之上。然后,我设置了默认的缓存行为,不需要签名url,这允许通过CloudFront发行版公开访问所有其他文件(如图像)。