通配子域指向适当的 S3/CloudFront 子目录
Wildcard subdomains point to appropriate S3/CloudFront subdirectories
我需要多个子域来指向 Amazon S3(同步到 CloudFront 分发版)上的个人 buckets/subdirectories,我在其中托管一些静态文件。
所以任何
SUBDOMAINNAME.example.com
自动指向
s3.amazonaws.com/somebucket/SUBDOMAINNAME
或
somedistributionname.cloudfront.net/SUBDOMAINNAME
有没有办法在没有 运行 重定向服务器的情况下完成此操作?
是否可以在不更改每个新子域的 DNS 记录的情况下完成,或者如果不能,以编程方式添加 DNS 规则?
就资源使用而言,最有效的方法是什么。 (可能有数百个子域,每个子域每天有数百个请求)
更新:这个答案在写的时候是正确的,下面描述的技术仍然完全可行,但可能不太理想,因为 Lambda@Edge 现在可以用来完成这个 objective,因为我在 Serving a multitude of static sites from a wildcard domain in AWS.
的回答中解释了
不,没有办法自动执行此操作。
Is there a way to accomplish this without running a server for redirection?
从技术上讲,您不需要重定向来完成此操作。您需要重写路径,这就是为什么您的最终问题的答案是 "no"——因为 Route 53(和一般的 DNS)不能做任何与路径相关的事情。
Route 53 确实支持通配符 DNS,但如果没有 CloudFront and/or S3 支持将主机 header 从 HTTP 请求放入路径(他们不支持)的机制,那帮助有限).
现在,这可以在 "zero-touch" 模式下轻松完成,其中包含单个 Route 53 *
通配符条目、为 *.example.com
配置的单个 CloudFront 分配以及一个或多个 EC2 instances 运行 HAProxy 重写请求路径并将请求转发到 S3 存储桶。基本配置文件中的一行将完成该请求重写:
http-request set-path /%[req.hdr(host)]%[path]
然后您需要代理将实际的存储桶端点主机名发送到 S3,而不是浏览器提供的主机名:
http-request set-header Host example-bucket.s3.amazonaws.com
代理会将修改后的请求发送到 S3,return S3 对 CloudFront 的响应,这将 return 对浏览器的响应。
但是,如果您不想采用这种方法,因为需要服务器,那么替代解决方案如下所示:
为每个子域配置 CloudFront 分配,为分配设置 alternate domain name 以匹配特定的子域。
将每个子域分布的 Origin 配置为指向同一个存储桶,将 origin path 设置为 /one-specific-subdomain.example.com
。在将请求发送到 S3 之前,CloudFront 会将 GET /images/funny-cat.jpg HTTP/1.1
的请求更改为 GET /one-specific-subdomain.example.com/images/funny-cat.jpg HTTP/1.1
,从而导致您描述的行为。 (这与我为 HAProxy 描述的行为的最终结果相同,但它是静态的,而不是动态的,因此每个子域一个分布;在这两种情况下都不会是 "redirect"——所以地址栏不会改变).
在 Route 53 中为每个子域配置一个 A-record 别名,指向子域的特定 CloudFront 分配。
这一切都可以通过 API、使用任何一个 SDK 或使用 aws-cli
以编程方式完成,这是一种非常简单的测试方法,原型,并在不编写太多代码的情况下编写此类内容的脚本。 CloudFront 和 Route 53 都完全 automation-friendly.
请注意,使用自己的 CloudFront 分配的每个站点都没有明显的缺点,因为您的命中率不会有所不同,并且分配没有单独收费——只有请求和带宽费用。
另请注意,CloudFront 有一个默认值 limit of 200 distributions per AWS account,但这是一个软限制,可以通过向 AWS 支持部门发送请求来增加。
通配符适用于 S3。我只是放了一个指向 IP 的 A 记录 *,它起作用了。
自 Lambda@edge 以来,这可以通过 Cloud Front "Viewer Request" 事件触发的 lambda 函数来完成。
这是这样一个 Lambda 函数的示例,其中像 foo.example.com/index.html
这样的请求将 return 来自您来源的文件 /foo/index.html
。
您需要一个带有 CNAME *.example.com
的 CF 分发包,以及指向它的 A 记录“*.example.com”
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const subdomain = getSubdomain(request);
if (subdomain) {
request.uri = '/' + subdomain + request.uri;
}
callback(null, request);
};
function getSubdomain(request) {
const hostItem = request.headers.host.find(item => item.key === 'Host');
const reg = /(?:(.*?)\.)[^.]*\.[^.]*$/;
const [_, subdomain] = hostItem.value.match(reg) || [];
return subdomain;
}
至于费用请看lambda pricing。当前定价为每百万请求 0.913 美元
我需要多个子域来指向 Amazon S3(同步到 CloudFront 分发版)上的个人 buckets/subdirectories,我在其中托管一些静态文件。
所以任何
SUBDOMAINNAME.example.com
自动指向
s3.amazonaws.com/somebucket/SUBDOMAINNAME
或
somedistributionname.cloudfront.net/SUBDOMAINNAME
有没有办法在没有 运行 重定向服务器的情况下完成此操作?
是否可以在不更改每个新子域的 DNS 记录的情况下完成,或者如果不能,以编程方式添加 DNS 规则?
就资源使用而言,最有效的方法是什么。 (可能有数百个子域,每个子域每天有数百个请求)
更新:这个答案在写的时候是正确的,下面描述的技术仍然完全可行,但可能不太理想,因为 Lambda@Edge 现在可以用来完成这个 objective,因为我在 Serving a multitude of static sites from a wildcard domain in AWS.
的回答中解释了不,没有办法自动执行此操作。
Is there a way to accomplish this without running a server for redirection?
从技术上讲,您不需要重定向来完成此操作。您需要重写路径,这就是为什么您的最终问题的答案是 "no"——因为 Route 53(和一般的 DNS)不能做任何与路径相关的事情。
Route 53 确实支持通配符 DNS,但如果没有 CloudFront and/or S3 支持将主机 header 从 HTTP 请求放入路径(他们不支持)的机制,那帮助有限).
现在,这可以在 "zero-touch" 模式下轻松完成,其中包含单个 Route 53 *
通配符条目、为 *.example.com
配置的单个 CloudFront 分配以及一个或多个 EC2 instances 运行 HAProxy 重写请求路径并将请求转发到 S3 存储桶。基本配置文件中的一行将完成该请求重写:
http-request set-path /%[req.hdr(host)]%[path]
然后您需要代理将实际的存储桶端点主机名发送到 S3,而不是浏览器提供的主机名:
http-request set-header Host example-bucket.s3.amazonaws.com
代理会将修改后的请求发送到 S3,return S3 对 CloudFront 的响应,这将 return 对浏览器的响应。
但是,如果您不想采用这种方法,因为需要服务器,那么替代解决方案如下所示:
为每个子域配置 CloudFront 分配,为分配设置 alternate domain name 以匹配特定的子域。
将每个子域分布的 Origin 配置为指向同一个存储桶,将 origin path 设置为
/one-specific-subdomain.example.com
。在将请求发送到 S3 之前,CloudFront 会将GET /images/funny-cat.jpg HTTP/1.1
的请求更改为GET /one-specific-subdomain.example.com/images/funny-cat.jpg HTTP/1.1
,从而导致您描述的行为。 (这与我为 HAProxy 描述的行为的最终结果相同,但它是静态的,而不是动态的,因此每个子域一个分布;在这两种情况下都不会是 "redirect"——所以地址栏不会改变).在 Route 53 中为每个子域配置一个 A-record 别名,指向子域的特定 CloudFront 分配。
这一切都可以通过 API、使用任何一个 SDK 或使用 aws-cli
以编程方式完成,这是一种非常简单的测试方法,原型,并在不编写太多代码的情况下编写此类内容的脚本。 CloudFront 和 Route 53 都完全 automation-friendly.
请注意,使用自己的 CloudFront 分配的每个站点都没有明显的缺点,因为您的命中率不会有所不同,并且分配没有单独收费——只有请求和带宽费用。
另请注意,CloudFront 有一个默认值 limit of 200 distributions per AWS account,但这是一个软限制,可以通过向 AWS 支持部门发送请求来增加。
通配符适用于 S3。我只是放了一个指向 IP 的 A 记录 *,它起作用了。
自 Lambda@edge 以来,这可以通过 Cloud Front "Viewer Request" 事件触发的 lambda 函数来完成。
这是这样一个 Lambda 函数的示例,其中像 foo.example.com/index.html
这样的请求将 return 来自您来源的文件 /foo/index.html
。
您需要一个带有 CNAME *.example.com
的 CF 分发包,以及指向它的 A 记录“*.example.com”
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const subdomain = getSubdomain(request);
if (subdomain) {
request.uri = '/' + subdomain + request.uri;
}
callback(null, request);
};
function getSubdomain(request) {
const hostItem = request.headers.host.find(item => item.key === 'Host');
const reg = /(?:(.*?)\.)[^.]*\.[^.]*$/;
const [_, subdomain] = hostItem.value.match(reg) || [];
return subdomain;
}
至于费用请看lambda pricing。当前定价为每百万请求 0.913 美元