问题
I'm trying to set up an alias for a domain that is purchased through route 53. The alias is going to point to a page in my site with a URL like this:
http://example.com/website/:id
My api sets up a hostedZone with the following params:
var params = {
CallerReference: req.body.projectId,
Name: req.body.domain,
HostedZoneConfig: {
Comment: `the zone created on ${today} for ${req.body.domain}`,
PrivateZone: false
}
};
In the next step, I'm setting up a DNS record with the following params:
var params = {
ChangeBatch: {
Changes: [
{
Action: "CREATE",
ResourceRecordSet: {
AliasTarget: {
DNSName: `http://example.com/website/${req.body.projectId}`,
EvaluateTargetHealth: false,
HostedZoneId: hostedZone.HostedZone.Id
},
Name: "example.com",
Type: "A"
}
}
],
},
HostedZoneId: hostedZone.HostedZone.Id
};
I get an error that my alias target name doesn't lie within the target zone. What step am I missing to set this up properly?
回答1:
DNS has no mechanism for handling paths, so what's being attempted here is something not possible in DNS. But it seems this was an attempt to solve a different problem.
Is there a way to route to a generic s3 bucket instead of a bucket with a matching name?
No... and yes.
S3 relies on what the browser thinks the hostname should be, as signified by the incoming Host
header, in order to send the request to the correct bucket.
Thus when S3 is used by itself, if a DNS entry points to a bucket, the bucket name must exactly match the hostname.
For different behavior, such as http://bucket.example.com
pointing to a bucket named example-bucket
, you need a reverse proxy to handle header rewriting so that when the browser specifies Host: bucket.example.com
, S3 receives a request with Host: example-bucket.s3.amazonaws.com
.
CloudFront provides such a reverse proxy capability.
When configuring a CloudFront distribution, you specify an Origin Domain Name (pointing to the bucket) and an Alternate Domain Name, which specifies what you want CloudFront to expect from the browser. CloudFront rewrites the request in-flight so that what S3 sees differs from what the browser sends.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/MigrateS3ToCloudFront.html
As noted on that page, the pricing structures of S3 and CloudFront are such that the cost difference between using S3 by itself or S3 + CloudFront can actually go either way -- it can actually cost slightly less to use both together, depending on the bucket location, the viewer location, the size of the objects, and the cache hit ratio (assuming you don't disable the CloudFront cache).
If you want https://website-1.example.com
to be served from your example-bucket
with a root path of website/1/
you can do that, too, but it gets a little trickier.
You can do this on a one-off, static basis by setting the Origin Path on the Origin configuration in CloudFront, since this field represents a path prefix that will be prepended onto each request before it's sent to the origin.
Or you can modify it dynamically using CloudFront with a Lambda@Edge trigger. Here's what that might look like.
'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-1.amazonaws.com';
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);
};
The above is an example I wrote and posted on the official AWS forum. It only works with the S3 web site hosting feature (not the REST endpoints) becauae this is required in order for the host header to be exposed to Lambda@Edge using the forwarded header whitelist.
It takes the prefix from the incoming hostname and rewrites it into a path prefix, while sending all requests to the same bucket.
Note that you will need a complementary function in an Origin Response trigger for handling responses, checking for HTTP 30x redirects. Because of the path prefixing we're doing, the opposite will need to be done on the reverse path, so that the Location
header's path will be correctly anchored.
Or just create a single CloudFront distribution for each of your sites -- AWS doesn't charge for the distribution itself, only for the requests it handles. Distributions can be easily created through automation -- scripting with aws-cli, or CloudFormation. The default limit on CloudFront distributions per account is 200, but AWS Support will increase this on request.
来源:https://stackoverflow.com/questions/49472636/route-53-alias-dns-record-the-alias-target-name-does-not-lie-within-the-target