AWS Cloudfront 作为具有自定义域的 Heroku 站点的 CDN

Posted

技术标签:

【中文标题】AWS Cloudfront 作为具有自定义域的 Heroku 站点的 CDN【英文标题】:AWS Cloudfront as CDN for Heroku Site with Custom Domain 【发布时间】:2018-02-17 15:28:14 【问题描述】:

最近,我从 AWS Route 53 (brianpatrickhummel.com) 购买了一个域来托管个人投资组合。投资组合站点已启动并运行,使用 S3 存储桶和 Cloudfront 作为 CDN。在投资组合网站上,访问者可以预览我构建的一些应用程序,这些应用程序使用 iframe 元素在网站内启动,我注意到我在 Heroku 部署的应用程序需要 10-20 秒才能加载,因为这些网站上的访问者很少平均,没有 CDN 服务。

因此,我开始研究使用 AWS Cloudfront 作为 CDN。我从一个 Heroku 应用开始,添加了一个自定义域,现在配置如下:

Domain Name: burger.brianpatrickhummel.com
DNS Target: burger.brianpatrickhummel.com.herokudns.com

最后一步是“配置应用的 DNS 提供商以指向 Heroku 提供的 DNS 目标”。在这一步和正确配置 Cloudfront 发行版之间,我陷入了混乱的漩涡。我不确定在 Cloudfront、Route 53 或两者中进行某些 DNS/CNAME 更改的位置。

没有太多专门与这三种技术(Heroku、Cloudfront、Route 53)相关的在线文档,我花了很多时间在这三篇文章之间翻来覆去,但无济于事:

Heroku - Using Amazon CloudFront CDN

Configuring Amazon Route 53 DNS for Your Heroku App

我相信必要的更改本质上很简单,并且非常感谢那些可能对这种特定配置有经验的人的任何见解。

---更新--- 我有最后一个问题,现在我的所有 Heroku 应用程序都已成功通过 Cloudfront 路由,我意识到所有具有生成 POST HTTP 请求的组件的应用程序都会收到 403 - 禁止错误。这与相应 AJAX 调用中的相对 URL 有什么关系:

$(document).on("click", ".saveButton", function () 
  var thisId = $(this).attr("id");
  $.ajax(
    method: "POST",
    url: "/save/" + thisId
  ).done(function ()  

我在 Cloudfront 文档中看到以下内容:

CloudFront 始终缓存对 GET 和 HEAD 请求的响应。您还可以将 CloudFront 配置为缓存对 OPTIONS 请求的响应。 CloudFront 不会缓存对使用其他方法的请求的响应。

与成功发送请求相比,处理来自 Heroku 应用服务器的响应的问题更多吗?

-- 更新 2 -- 根据 Cloudfront 文档中的此声明,我认为这与 HTTP/HTTPS 有关:

CloudFront 不会将 DELETE、OPTIONS、PATCH、POST 或 PUT 请求从 HTTP 重定向到 HTTPS。如果您将缓存行为配置为重定向到 HTTPS,CloudFront 会使用 HTTP 状态代码 403(禁止)响应该缓存行为的 HTTP DELETE、OPTIONS、PATCH、POST 或 PUT 请求。

Heroku 声明:

如果您想使用 SSL 为 Cloudfront 资产提供服务,您只需在 Amazon 提供给您的分发域上使用 HTTPS。请注意,虽然您可以为此创建 CNAME,但通过 CNAME 和 SSL 提供 Cloudfront 资产需要额外费用。

在 AWS Cloudfront Distribution Cache Behavior 设置中,您可以选择 查看者协议政策有以下三个选项:

如果您希望 CloudFront 允许查看者使用 HTTP 或 HTTPS 访问您的 Web 内容,请指定 HTTP 和 HTTPS。如果您希望 CloudFront 将所有 HTTP 请求重定向到 HTTPS,请指定将 HTTP 重定向到 HTTPS。如果您希望 CloudFront 需要 HTTPS,请指定 HTTPS Only。

Cloudfront 文档继续指出:

将 HTTP 重定向到 HTTPS 查看者可以使用这两种协议,但 HTTP 请求会自动重定向到 HTTPS 请求。 CloudFront 返回 HTTP 状态代码 301(永久移动)以及新的 HTTPS URL。然后查看器使用 HTTPS URL 将请求重新提交到 CloudFront。

当查看器发出重定向到 HTTPS 请求的 HTTP 请求时,CloudFront 会为这两个请求收费。对于 HTTP 请求,仅针对请求和 CloudFront 返回给查看器的标头收费。对于 HTTPS 请求,费用是针对请求以及您的源返回的标头和对象。

仅 HTTPS 只有使用 HTTPS 的查看者才能访问您的内容。如果查看器发送的是 HTTP 请求而不是 HTTPS 请求,CloudFront 会返回 HTTP 状态代码 403(禁止)并且不返回对象。

天哪,我不知道托管个人网站会有多复杂!

【问题讨论】:

【参考方案1】:

域名:burger.brianpatrickhummel.com

您将在 Route 53 中将其指向 CloudFront...但在执行此操作之前,您需要创建一个新的 CloudFront 分配并将该主机名配置为分配的备用域名。

DNS 目标:burger.brianpatrickhummel.com.herokudns.com

在创建分配 CloudFront 时将其配置为源域名。

在缓存行为设置中,将 Host 标头列入白名单,以便 Heroku 了解请求针对的是哪个站点。

【讨论】:

感谢您的信息!我创建了一个以 Heroku DNS 目标作为源域名的 Cloudfront 分配(并将 Heroku 应用程序域名添加为 CNAME),然后创建了一个 Route 53 记录集,其名称与 Cloudfront CNAME 匹配,类型:A,别名:是的,然后选择 Cloudfront Distribution 作为 Alias Target ......它工作得很好!!我看到有人提到将 Route 53 记录集类型配置为 CNAME。我选择了 Type A,它似乎可以工作,当我尝试使用 CNAME 时,Alias Target 下拉菜单中没有可选选项。 优秀。将别名设置为“是”的A 记录是正确的选择。如果您将别名设置为否,则可以使用 CNAME,方法是在框中键入 CloudFront 终端节点主机名,但您不希望这样A 具有 Alias = Yes 的记录的查找速度大约是两倍,并且对于指向 CloudFront、S3 或 ELB 等 AWS 服务的 A 记录别名的查询是免费的,但 CNAME 查询不是免费的。实际上,您的帐单上有一个 0.00 美元的订单项,而且它不是免费的“层级”——这些都是免费的。【参考方案2】:

这是我要做的步骤,

既然你已经在 53 号公路上,

从 ACM 获取免费 SSL

确认您对域电子邮件地址的 SSL 验证。 确保它看起来是绿色的,如下所示,

也使用 SSL 和 CNAME 将其分配给 CloudFront Endpoint

您还将看到在 Route53 中为此 SSL 端点自动创建一个 cname。

如果您 p​​ing burger.brianpatrickhummel.com,它应该从 clound 前端响应。

现在在 Cloudfront 中设置 Origins 以将其指向您的端点以及所需的所有缓存设置。如果不需要缓存设置,可以全部设置为0,这样cloudfront就不会缓存任何数据了。

在您的 Cloudront 模式中,确保您在末尾有 *,以便它匹配所有 url 模式以将其转发到您的端点。

如果您的端点需要保护,您可以从 Cloudfront 传入额外的标头,并确保请求来自 Cloudfront,而不是任何公共端点。

【讨论】:

【参考方案3】:

我不确定我在哪里进行某些 DNS/CNAME 更改,在 Cloudfront、Route 53 或两者兼而有之

既然 Route53 是 DNS 服务(不是 CloudFront),那么您将在 Route53 中创建 CNAME 记录。您想在 Route53 中创建一条 CNAME 记录,将您的子域指向 CloudFront。然后,您需要配置 CloudFront 以了解它需要通过配置备用域名字段来为该域提供服务。

【讨论】:

【参考方案4】:

似乎Host 是no longer trusted and accepted by heroku。它将不再正确链接到该站点

请改用Origin Custom Header

自定义标头的名称会经过一些解析和大小写更改,因此要对其进行调试,请添加此命令以打印请求中提供的相关标头。

puts request.headers.env.reject  |key| key.to_s.include?('.') 

您应该在那里看到您的标题,但可能格式不同。

作为参考,我的标头是 X-Request-ID(这是 recommended by Heroku 用于额外用途),它被转换为 HTTP_X_REQUEST_ID

【讨论】:

以上是关于AWS Cloudfront 作为具有自定义域的 Heroku 站点的 CDN的主要内容,如果未能解决你的问题,请参考以下文章

AWS:如何为自定义域名配置 Cloudfront

使用 AWS CloudFront 时,如何向公众隐藏自定义源服务器?

AWS Cloudfront 将 JavaScript 模块作为错误的 MIME 类型(“Text/Plain”)提供服务

AWS Cloudfront 将 JavaScript 模块作为错误的 MIME 类型(“Text/Plain”)提供服务

如何使用 AWS CDK 将域别名添加到现有 CloudFront 分配

通过 API 将域添加到 AWS Cloudfront 分发