【问题标题】:Serving a multitude of static sites from a wildcard domain in AWS从 AWS 中的通配符域为多个静态站点提供服务
【发布时间】:2018-09-23 13:26:48
【问题描述】:

我有一个非常具体的问题,我们有一个我们已经拥有并维护的系统,该系统涉及使用子域将人们路由到特定的应用程序。

在传统服务器上,如下所示;我们有一个通配符子域 *.domain.com,它路由到 nginx 并提供一个文件夹

所以 myapp.domain.com > nginx > 提供 myapp 应用程序文件夹 > myapp 文件夹包含一个静态站点

我正在尝试以某种方式将其迁移到 AWS,我基本上需要在 AWS 中做类似的事情,我玩弄了将每个静态应用程序放入 s3 存储桶,然后在路由 53 中的通配符域的想法,但是我不确定 s3 如何知道要提供哪个文件夹,因为该功能不是路线 53 的一部分

大家有什么建议吗?

感谢大家的帮助

【问题讨论】:

    标签: amazon-web-services amazon-s3 amazon-route53


    【解决方案1】:

    CloudFront + Lambda@Edge + S3 可以做到这一点“无服务器”。

    Lambda@Edge 是一项 CloudFront 增强功能,它允许将请求和响应的属性表示为简单的 JavaScript 对象并对其进行操作。触发器可以在请求处理期间触发,可以在检查缓存之前(“查看器请求”触发器)或在请求继续到后端(“源服务器”,在本例中为 S3 网站托管端点)之前触发在缓存未命中(“源请求”触发器)之后......或在响应处理期间,在从源接收到响应之后但在考虑将其存储在 CloudFront 缓存中之前(“源响应”触发器),或在完成对浏览器的响应(“查看器响应”触发器)。响应触发器也可以检查原始请求对象。

    以下 sn-p 是我最初在 AWS 论坛上的 posted。这是一个原始请求触发器,它将原始主机名与您的模式进行比较(例如,域必须匹配 *.example.com),如果匹配,则主机名前缀 subdomain-here.example.com 是从为子域命名的文件夹中提供的请求。

    lol.example.com/cat.jpg        -> my-bucket/lol/cat.jpg
    funny-pics.example.com/cat.jpg -> my-bucket/funny-pics/cat.jpg
    

    通过这种方式,来自任意多个子域的静态内容都可以从一个存储桶中提供。

    为了访问原始传入的 Host 标头,需要将 CloudFront 配置为 whitelist the Host header for forwarding to the origin,即使 Lambda 函数执行的最终结果是在源端实际看到之前修改该值。

    代码其实很简单——以下大部分是解释性cmets。

    'use strict';
    
    // if the end of incoming Host header matches this string, 
    // strip this part and prepend the remaining characters onto the request path,
    // along with a new leading slash (otherwise, the request will be handled
    // with an unmodified path, at the root of the bucket)
    
    const remove_suffix = '.example.com';
    
    // provide the correct origin hostname here so that we send the correct 
    // Host header to the S3 website endpoint
    
    const origin_hostname = 'example-bucket.s3-website.us-east-2.amazonaws.com'; // see comments, below
    
    exports.handler = (event, context, callback) => {
        const request = event.Records[0].cf.request;
        const headers = request.headers;
        const host_header = headers.host[0].value;
    
        if(host_header.endsWith(remove_suffix))
        {
            // prepend '/' + the subdomain onto the existing request path ("uri")
            request.uri = '/' + host_header.substring(0,host_header.length - remove_suffix.length) + request.uri;
        }
    
        // fix the host header so that S3 understands the request
        headers.host[0].value = origin_hostname;
    
        // return control to CloudFront with the modified request
        return callback(null,request);
    };
    

    请注意,来自 S3 的索引文档和重定向可能还需要 Origin Response 触发器来针对原始请求规范化 Location 标头。这将取决于您使用的 S3 网站功能。但以上是一个说明总体思路的工作示例。

    请注意,const origin_hostname 需要设置为 CloudFront 源设置中配置的存储桶的终端节点主机名。在此示例中,存储桶位于 us-east-2 中,并且网站托管功能处于活动状态。

    【讨论】:

    • 谢谢!但是,如果不进行一些更改,这将无法正常工作。 1.,您需要将Host标头列入白名单,以便传递原始传入请求主机,例如host_header(你posted原来在这里!)(AWS Docs)。 2.origin_hostname不应该包含s3-website-us-east-1部分。将其更改为 example-bucket.s3.amazonaws.com
    • @mfink 感谢您的反馈。我确实忘记提及Host 标头白名单。但是,对于origin_hostname,如果启用了网站托管功能并且您使用网站端点作为源域名,则使用存储桶的 REST 端点主机名(例如 example-bucket.s3.amazonaws.com)将不起作用——即在这个应用程序中通常是这种情况,因为这是渲染自动索引文档所必需的。
    • 感谢您澄清origin_hostname。我想我的原始设置设置为 s3 存储桶名称 sans s3-website-us-east-1。我的 s3 也被配置为一个网站,所以这可以解释为什么我需要将 index.html 指定为我的Default Root Object,而不是将我的来源指定为网站 url。
    • @mfink 是的。默认根对象仅处理实际路径/。来自网站托管功能的索引文档可以在任何路径隐式呈现任何 index.html 文件(/foo/bar 重定向到 /foo/bar/,隐式呈现 /foo/bar/index.html... 但在这种情况下可能需要更多 Lambda@Edge,以便Location 标头是正确的)。如果您的存储桶配置为网站,您可能希望使用网站端点作为源域名:stackoverflow.com/a/34065543/1695906
    • @Michael-sqlbot 这是否可以路由到不同的 s3 存储桶而不是单个存储桶中的文件夹?
    【解决方案2】:
    1. 创建 Cloudfront 分发版

    2. 在云端分发中添加所有Alternate CNAMEs记录

    3. 添加自定义源作为 EC2 服务器。

    4. 根据您的要求设置行为。

    5. 在服务器中配置 nginx 虚拟主机以路由到特定文件夹。

    【讨论】:

      猜你喜欢
      • 2019-06-10
      • 2018-03-20
      • 2019-11-28
      • 2017-05-22
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      相关资源
      最近更新 更多