4

My objective

I have a number of domains (e.g. 10 or 20) and I would like to redirect any visitors to anywhere on those pages to one page on another domain (for example my stackoverflow.com profile page).

This includes

  1. apex domain using http (e.g. http://mydomain01.com)
  2. apex domain using https (e.g. https://mydomain01.com)
  3. sub domains using http (e.g. http://www.mydomain01.com or http://blog.mydomain01.com)
  4. sub domains using https (e.g. https://www.mydomain01.com or https://blog.mydomain01.com)
  5. any paths (e.g. http://mydomain01.com/some_path or https://www.mydomain01.com/another/path.html)

plus the same for all my other domains (mydomain02.com, mydomain03.com, etc.; each with the above use cases).

My research

  1. This AWS article explains how to redirect internet traffic from an apex domain to another domain (case #1 in my This includes list above) using AWS S3 and AWS Route 53: This works for http, but not for https.
  2. This AWS article explains how to redirect internet traffic for a number of cases (by the looks of it, covering all cases in my This includes list above) using AWS S3, AWS Route 53 and AWS CloudFront: This works for both http and https. (Also talks about using an Application Load Balancer, but I guess that's beyond the scope here...)
  3. This AWS article adds some more details on setting up a CloudFront distribution and how to get insight into log files.
  4. This AWS article documents redirection rules to use advanced conditional redirects: Not sure if I need to go there to accomplish my goal, so haven't really looked into that yet.

Plus, there are obviously plenty of SO questions (see Related to the right of this question) and other posts on the subject; problem with most of those is that they use screenshots from previous versions of the AWS Console UI: Most of the contents should still be the same, but correlating those screenshots to the current UI IMO adds another layer of confusion.

Key takeaways from the AWS (and other) docs:

  1. I need to create a bucket in AWS S3 and configure redirection in it,
  2. I need to create a distribution in AWS CloudFront;
  3. in order to use a custom domain in CloudFront, I need to create a certificate in AWS ACM,
  4. I need to create a hosted zone in AWS Route 53 and configure records in it.

My work so far

The latest AWS CLI is installed, region and output are configured in ~/.aws/config, credentials are set up in ~/.aws/credentials (each for every AWS account); AWS_* environment variables are exported.

I am using AWS region US East (N. Virginia) (us-east-1) for everything to prevent any additional issues caused by AWS resources not being available in a region.

$ aws --version
aws-cli/2.2.23 Python/3.9.6 Darwin/19.6.0 source/x86_64 prompt/off

I omit any shell prompts or > shell line continuation characters for easier copying from this post into the shell.

Set up an S3 bucket

Warning: This creates an "all public" bucket without any access restrictions. In this case, this should not matter as there is no bucket contents to protect, but such a public bucket is a bad practice in general. Also, I'm using a public bucket to prevent any additional issues caused by access restrictions: First, get it work; second, make it secure.

create the bucket

aws s3api create-bucket --bucket mydomain01.com
  • response:
{
    "Location": "/mydomain01.com"
}

set up redirection

aws s3api put-bucket-website --bucket mydomain01.com --website-configuration \
    '{ "RedirectAllRequestsTo": { "HostName": "stackoverflow.com/users/217844/ssc" } }'
  • no response

Gotcha: The S3 bucket name must match the apex domain name.

Using any bucket name but mydomain01.com (for my example) seems to fail without any indication as to the cause. The AWS docs don't really make this very clear - in fact, I am still not sure if I massively misunderstand something here, but from what I can tell, the official AWS documentation is actually somewhat sloppy on that - IMO - crucial key point: For example, #2 just says

  1. Create an S3 bucket with a global unique name.

which could be any globally unique name. #1 mentions that in some way - once you know how to read those bits...

On a side note, that article #2 continues to confuse me with

If you aren't using a custom domain ...

Why would I not be using a custom domain ?!? The whole point is to redirect my custom domain, isn't it ?!? Well, anyway...

Gotcha: Must not prepend protocol to hostname.

Neither the AWS Console nor the AWS CLI seem to test if a protocol (http:// or https://) was entered in the Host name UI field / passed in the HostName JSON string. However, if one is prepended, the redirect fails; see test redirection below.

Gotcha: AWS S3 Console UI bug.

After redirection has been set up, the AWS Console displays clickable link in its UI to the bucket URL (http://mydomain01.com.s3-website-us-east-1.amazonaws.com) at the very bottom of the bucket's Properties tab, in the Static website hosting section.

Clicking that link fails to open the page, seemingly because the AWS Console messes up the URL and tries to open http://https//stackoverflow.com/users/217844/ssc/, no matter the protocol.

test redirection

  • using HTTPie in the shell instead of curl or wget because that's what the cool kids seem to use nowadays
  • copy the link from AWS Console in browser to shell
http http://mydomain01.com.s3-website-us-east-1.amazonaws.com/
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Date: Mon, 02 Aug 2021 12:39:09 GMT
Location: http://stackoverflow.com/users/217844/ssc/
Server: AmazonS3
x-amz-id-2: rakAqUMnRraGvo/WkSa6AnbuhWn/9YZX/CAlI/OJQKYoWp/OdQIbyhsvHSwNved3suwMdgglqpE=
x-amz-request-id: C5BBG833Q9TQ9J6X

--> seems to work

  • test the redirection if the protocol was erroneously prepended to the host name; note the broken Location url:
http http://mydomain01.com.s3-website-us-east-1.amazonaws.com/
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Date: Mon, 02 Aug 2021 12:52:10 GMT
Location: http://https://stackoverflow.com/users/217844/ssc/
Server: AmazonS3
x-amz-id-2: Ee2/ob0faTpRdp6mGITdmClozXNmF1Q2oTbPioms8O91VA8n5VA3MoHhveeFz7v2VS65YKFKlDA=
x-amz-request-id: ZJP653R50YD5HSRS

My questions #1

NOTE: I had these questions when I started out writing this; I think I was able to answer them myself since (see test www sub domain record below). Someone please correct me if I'm wrong:

  1. Q: Does the "bucket name == domain name" requirement apply even if I use CloudFront ?
    A: Yes.
  2. Q: Do I need to create one bucket each for the apex domain and every subdomain ? so, in my example
    • mydomain01.com
    • www.mydomain01.com
    • blog.mydomain01.com ?
      A: Yes.

Set up an Route 53 hosted zone

create the hosted zone

aws route53 create-hosted-zone --caller-reference "$(date '+%Y%m%d-%H%M%S')" --name mydomain01.com
  • response
{
    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z123456789EXAMPLE0SKX",
    "HostedZone": {
        "Id": "/hostedzone/Z123456789EXAMPLE0SKX",
        "Name": "mydomain01.com.",
        "CallerReference": "20210802-150736",
        "Config": {
            "PrivateZone": false
        },
        "ResourceRecordSetCount": 2
    },
    "ChangeInfo": {
        "Id": "/change/C1234567890SKXEXAMPLE",
        "Status": "PENDING",
        "SubmittedAt": "2021-08-02T13:07:37.860000+00:00"
    },
    "DelegationSet": {
        "NameServers": [
            "ns-1234.awsdns-12.com",
            "ns-5678.awsdns-34.co.uk",
            "ns-1234.awsdns-56.net",
            "ns-5678.awsdns-78.org"
        ]
    }
}
  • take note of the hosted zone ID Z123456789EXAMPLE0SKX, needed in the next steps

create a record for the apex domain

{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "mydomain01.com.",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z3AQBSTGFYJSTF",
          "DNSName": "s3-website-us-east-1.amazonaws.com",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}

Gotcha: Must use verbatim s3-website-us-east-1.amazonaws.com for DNSName.

AWS docs talk in all sort of places about example.com or example.com.s3-website-us-east-1.amazonaws.com, etc. In this case, this is not some example to be replaced by own values (e.g. mydomain01.com.s3-website-us-east-1.amazonaws.com), but the verbatim value from the table, i.e. s3-website-us-east-1.amazonaws.com.

Gotcha: Must not prepend protocol to hostname.

Similar to the gotcha above, both AWS Console and the AWS CLI gladly accept a protocol (http:// or https://) prepended to the value entered in the Host name UI field / passed as DNSName. At least, this looks very wrong in the Console, e.g. http\072\057\057mydomain01.s3-website-us-east-1.amazonaws.com.

Both gotchas are somewhat mitigated in the AWS Console where values can be selected from a dropdown box when a record is created or edited; when using the AWS CLI, you must double-check what you send.

The same gotcha and mitigation applies to the Record name UI field / Name JSON value.

create a record for the apex domain, cont.

  • use jq for a quick test the temp file contains valid json
jq . < change-batch.apex.json 1> /dev/null
  • no output --> valid JSON
aws route53 change-resource-record-sets --hosted-zone-id Z123456789EXAMPLE0SKX \
    --change-batch "file://$(pwd)/change-batch.apex.json"
  • response
{
    "ChangeInfo": {
        "Id": "/change/C1234567890EXAMPLESKX",
        "Status": "PENDING",
        "SubmittedAt": "2021-08-02T14:20:09.370000+00:00"
    }
}

test apex domain record

  • test http
http http://mydomain01.com
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Date: Mon, 02 Aug 2021 15:06:08 GMT
Location: http://stackoverflow.com/users/217844/ssc/
Server: AmazonS3
x-amz-id-2: EfDtCxif2iV4eInskirSBAOjQS7o9arzJCeZjscF6mW7cwwmm9Nxb7QJT50x2kjdslX2fOxA+lk=
x-amz-request-id: WM7K9TDEF75A6P1V

--> looks good

  • test http with a path
http http://mydomain01.com/some/path
 ... similar output as above ...
  • test https
http https://mydomain01.com

http: error: ConnectionError: HTTPSConnectionPool(host='mydomain01.com', port=443):
  Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x101a48100>:
    Failed to establish a new connection: [Errno 60] Operation timed out')) while doing a GET request to URL: https://mydomain01.com/
  • (response wrapped for readability)

--> times out (after 60s ?) - as expected: redirecting using an S3 bucket does not work with https (see above)

Gotcha: DNS change propagation delay.

AWS and Google are very fast in terms of propagating changes to DNS settings (as in seconds or minutes), but there might be other, "slower" name servers involved. Bypass them as described here to eliminate that source of confusion. That approach only works in macOS, but the concept is the same for any OS.

Gotcha: Browser cache.

When testing DNS changes not in the shell, but in the browser, the browser might get results from its cache. I do most of my work using Chrome, but use Firefox (or Safari) for testing, so I can clear the entire cache before every test to eliminate that potential issue - without getting logged out of Google, AWS, etc.

create a record for www sub domain

  • the only difference is the Name JSON value
sed -e 's|mydomain01.com.|www.mydomain01.com.|g' change-batch.apex.json > change-batch.www.json
aws route53 change-resource-record-sets --hosted-zone-id Z123456789EXAMPLE0SKX \
    --change-batch "file://$(pwd)/change-batch.www.json
  • response similar as above

test www sub domain record

  • test http
http http://www.mydomain01.com
HTTP/1.1 404 Not Found
Content-Length: 363
Content-Type: text/html; charset=utf-8
Date: Mon, 02 Aug 2021 15:28:05 GMT
Server: AmazonS3
x-amz-id-2: MGLcynq1iEGKh+pT6N6iRpCuQSN243q/5zm2Y7rXTnM7iW9nvDokF6s20xEUBr7QiEtBPEzZmII=
x-amz-request-id: TK83G35EMYFR8SKX

<html>
<head><title>404 Not Found</title></head>
<body>
<h1>404 Not Found</h1>
<ul>
<li>Code: NoSuchBucket</li>
<li>Message: The specified bucket does not exist</li>
<li>BucketName: www.mydomain01.com</li>
<li>RequestId: TK83G35EMYFR8SKX</li>
<li>HostId: MGLcynq1iEGKh+pT6N6iRpCuQSN243q/5zm2Y7rXTnM7iW9nvDokF6s20xEUBr7QiEtBPEzZmII=</li>
</ul>
<hr/>
</body>
</html>
  • I think that answers the second of My questions #1 above: I need one S3 bucket per apex/sub domain to forward.

Set up a CloudFront distribution

create a certificate

  • AWS ACM request-certificate docs
  • the certificate is supposed to work for the apex and all sub domains, so need to add another name to this certificate / pass --subject-alternative-names; see this AWS article (the upper blue box).
  • add quotes around *.mydomain01.com so the shell does not interpret the *
aws acm request-certificate --domain-name mydomain01.com --validation-method DNS \
    --subject-alternative-names '*.mydomain01.com'
  • response:
{
    "CertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/12345678-90ab-cdef-1234-1234567890ab"
}
  • 123456789012 is my AWS account ID; everything after certificate/ is just a UUID

get certificate details

  • AWS ACM describe-certificate docs
  • save response to temporary local file; extract ResourceRecord.Name and ResourceRecord.Value using jq
  • needed for the AWS Route 53 record that proves I own mydomain01.com
  • alternatively, use --query parameter with aws acm describe-certificate
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:123456789012:certificate/12345678-90ab-cdef-1234-1234567890ab" \
 > describe-certificate.json
jq -r '.Certificate.DomainValidationOptions[0].ResourceRecord.Name' describe-certificate.json
_1234567890abcdef1234567890abcdef.mydomain01.com.

jq -r '.Certificate.DomainValidationOptions[0].ResourceRecord.Value' describe-certificate.json 
_1234567890abcdef1234567890abcdef.weirdchars.acm-validations.aws.

create a Route 53 record for certificate validation

  • will be automatically checked by AWS ACM and the certificate will be validated once this record is found
  • as before, use a temporary local file change-batch.cert.json, see e.g. create a record for the apex domain; contents:
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "_1234567890abcdef1234567890abcdef.mydomain01.com.",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "_1234567890abcdef1234567890abcdef.weirdchars.acm-validations.aws."
          }
        ]
      }
    }
  ]
}
  • shell command:
aws route53 change-resource-record-sets --hosted-zone-id Z123456789EXAMPLE0SKX \
    --change-batch "file://$(pwd)/change-batch.cert.json
  • response similar as when creating records above
  • NOTE: It might take a couple of minutes for ACM to validate the certificate.

create the CloudFront distribution

  • AWS CloudFront create-distribution docs
  • again, CallerReference must simply be a unique string; use e.g. date '+%Y%m%d-%H%M%S' in shell to create and copy into file; see create the hosted zone
  • as before, use a temporary local file create-distribution.json for complex values; contents below
  • MinimumProtocolVersion: get value from this AWS article
  • OriginProtocolPolicy: using http-only because the origin (the S3 bucket) can do only http
  • ViewerProtocolPolicy: using redirect-to-https as the whole point of creating this distribution is to redirect from http to https
  • NOTE: I don't know (and the AWS docs don't tell) which fields are mandatorily required; the AWS CLI command displays a clear and detailed message if something about the data sent is missing or wrong.
{
    "CallerReference": "20210802-191725",
    "Aliases": {
        "Quantity": 2,
        "Items": ["mydomain01.com", "*.mydomain01.com"]
    },
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "mydomain01.com.s3.us-east-1.amazonaws.com_20210802-191725",
                "DomainName": "mydomain01.com.s3.us-east-1.amazonaws.com",
                "CustomOriginConfig": {
                    "HTTPPort": 80,
                    "HTTPSPort": 443,
                    "OriginProtocolPolicy": "http-only"
                }
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "mydomain01.com.s3.us-east-1.amazonaws.com_20210802-191725",
        "ForwardedValues": {
            "QueryString": false,
            "Cookies": {
                "Forward": "none"
            },
            "Headers": {
                "Quantity": 0
            },
            "QueryStringCacheKeys": {
                "Quantity": 0
            }
        },
        "TrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ViewerProtocolPolicy": "redirect-to-https",
        "MinTTL": 0,
        "AllowedMethods": {
            "Quantity": 2,
            "Items": [
                "HEAD",
                "GET"
            ],
            "CachedMethods": {
                "Quantity": 2,
                "Items": [
                    "HEAD",
                    "GET"
                ]
            }
        },
        "SmoothStreaming": false,
        "DefaultTTL": 86400,
        "MaxTTL": 31536000,
        "Compress": false,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": ""
    },
    "CacheBehaviors": {
        "Quantity": 0
    },
    "CustomErrorResponses": {
        "Quantity": 0
    },
    "Comment": "",
    "Logging": {
        "Enabled": false,
        "IncludeCookies": false,
        "Bucket": "",
        "Prefix": ""
    },
    "PriceClass": "PriceClass_All",
    "Enabled": true,
    "ViewerCertificate": {
        "ACMCertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/12345678-90ab-cdef-1234-1234567890ab",
        "MinimumProtocolVersion": "TLSv1.2_2021",
        "SSLSupportMethod": "sni-only"
    },
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none",
            "Quantity": 0
        }
    },
    "WebACLId": "",
    "HttpVersion": "http2",
    "IsIPV6Enabled": true
}
  • shell command:
  • NOTE: add --no-cli-pager to disable paging and store response in temporary local file for inspection
aws --no-cli-pager cloudfront create-distribution \
    --distribution-config "file://$(pwd)/create-distribution.json"
 > create-distribution.response.json
  • response: a large JSON structure, mostly the config sent with some distribution meta info

Gotcha: CloudFront distribution takes a moment to deploy.

In the Distributions overview, there is a Last modified field that says Deploying for a while after every change; depending on screen and browser window width, this field might be hidden, so the UI might looks like the distribution is up and running while in fact, it is not.

test distribution

  • get DomainName from response
jq -r '.Distribution.DomainName' create-distribution.response.json
abcdefghij1234.cloudfront.net
  • test http
http http://abcdefghij1234.cloudfront.net
HTTP/1.1 301 Moved Permanently
Connection: keep-alive
Content-Length: 183
Content-Type: text/html
Date: Mon, 02 Aug 2021 20:14:27 GMT
Location: https://abcdefghij1234.cloudfront.net/
Server: CloudFront
Via: 1.1 8640a37b586353bc916562c577770223.cloudfront.net (CloudFront)
X-Amz-Cf-Id: ooT0Y1QvDE7_yoRmb0p0Un2Db6O713rBvudtmz1xer7YwEU0GE8smw==
X-Amz-Cf-Pop: HAM50-C2
X-Cache: Redirect from cloudfront

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>CloudFront</center>
</body>
</html>

So the distribution redirects from http://abcdefghij1234.cloudfront.net to https://abcdefghij1234.cloudfront.net - as it should; that's what it was created for.

  • test https
HTTP/1.1 403 Forbidden
Connection: keep-alive
Content-Type: application/xml
Date: Mon, 02 Aug 2021 20:14:35 GMT
Server: AmazonS3
Transfer-Encoding: chunked
Via: 1.1 c3e656776c8a9f0e1ea24405ab1dcc85.cloudfront.net (CloudFront)
X-Amz-Cf-Id: or4SC8urWEv_8c3jDURv5IINwFU1TDVLSQ3_X7tya7Ncz8ujyz0-IQ==
X-Amz-Cf-Pop: HAM50-C2
X-Cache: Error from cloudfront
x-amz-bucket-region: us-east-1

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>EAST1CM5WJR8QM3S</RequestId>
  <HostId>zF2dJm2vsuSM633NHuzcA5VqrCrNkfYGu31FRmKKIkebuI5+6l5DlVnr4kk9be262hcqktoiROw=</HostId>
</Error>
  • (xml formatted for readability)

That does not look good. Not sure if that is to be expected ?!?

Update the AWS Route 53 records

  • change from using the S3 bucket to using the CloudFront distribution
  • as before, create a temporary local file change-batch.apex.updatejson by seding the earlier file change-batch.apex.json
  • use UPSERT instead of CREATE: The record exists already and must be updated.
  • HostedZoneId: replace old value Z3AQBSTGFYJSTF (for S3) by Z2FDTNDATAQYW2, some magic value taken from change-resource-record-sets docs
  • DNSName: quote from change-resource-record-sets docs

Specify the domain name that CloudFront assigned when you created your distribution.

Your CloudFront distribution must include an alternate domain name that matches the name of the resource record set. For example, if the name of the resource record set is acme.example.com, your CloudFront distribution must include acme.example.com as one of the alternate domain names.

--> replace s3-website-us-east-1.amazonaws.com (for S3) by abcdefghij1234.cloudfront.net:

sed -e 's|CREATE|UPSERT|g' \
    -e 's|Z3AQBSTGFYJSTF|Z2FDTNDATAQYW2|g' \
    -e 's|s3-website-us-east-1.amazonaws.com|abcdefghij1234.cloudfront.net|g' \
    change-batch.apex.json > change-batch.apex.update.json
  • file contents:
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "mydomain01.com.",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "abcdefghij1234.cloudfront.net",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}
  • shell command
aws route53 change-resource-record-sets \
    --hosted-zone-id Z123456789EXAMPLE0SKX \
    --change-batch "file://$(pwd)/change-batch.apex.update.json"
  • response similar as when creating records above

test apex domain record

  • test http
http http://mydomain01.com
HTTP/1.1 301 Moved Permanently
Connection: keep-alive
Content-Length: 183
Content-Type: text/html
Date: Mon, 02 Aug 2021 19:08:27 GMT
Location: https://mydomain01.com/
Server: CloudFront
Via: 1.1 2408979685aa1bdb752824d292e63bf7.cloudfront.net (CloudFront)
X-Amz-Cf-Id: Ww60Ol_0fdR8SsgcHeRYUd_de1rVejX6w_wuK80aR21e3IHstB-irA==
X-Amz-Cf-Pop: HAM50-C2
X-Cache: Redirect from cloudfront

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>CloudFront</center>
</body>
</html>
  • the response now comes from CloudFront and no longer from S3, so the updated DNS record seems to work :-)
  • test http with a path
http http://mydomain01.com/some/path
 ... similar output as above ...

--> looks good

  • test https
http https://mydomain01.com
HTTP/1.1 403 Forbidden
Connection: keep-alive
Content-Type: application/xml
Date: Mon, 02 Aug 2021 18:53:51 GMT
Server: AmazonS3
Transfer-Encoding: chunked
Via: 1.1 ea89c67081222c8c680e7a37ad75f4f0.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 5prv5_g5zXOX3aRBp2Gq64JJPuwC2o5dHIp9RCAHm6Ls8hK6EFghXw==
X-Amz-Cf-Pop: HAM50-C2
X-Cache: Error from cloudfront
x-amz-bucket-region: us-east-1

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>T78ASF3FA9QGV4T5</RequestId>
  <HostId>xaEgwEtbeesL4XfxMdxVoPAt9Lpb1ZDM9Fs5W4htBbcWNbV9sMUTjVAPIuWwAQ3Xh1yRhh4b4Ts=</HostId>
</Error>
  • (as before, xml formatted for readability)

NOTE: This response comes from AmazonS3, not from CloudFront as the previous one. The S3 bucket has no access restrictions whatsoever in place - so how can there be an access denied ?!?

double-check bucket permissions

aws s3api get-bucket-policy --bucket mydomain01.com

An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist

That matches the empty Bucket policy field in the AWS S3 Console - but is it really ok that there is no bucket policy at all ?!?

Now that look back at test distribution above, I see that the response to accessing abcdefghij1234.cloudfront.net directly also come from S3, not from CloudFront, so the problem seems to be pretty clear:

My questions #2

  1. Why does the S3 bucket deny access ?
  2. Is it normal for an S3 bucket to have no access policy at all ? Don't usually have "public" buckets a policy that explicitly allows access to anyone ?
  3. Similar to one S3 bucket per apex / sub domain, do I also need one CloudFront distribution per apex / sub domain ?
  4. If so, I guess adding *.mydomain01.com as alternate domain to the certificate (and the distribution) does not really make any sense, does it ?!? I'd also need one certificate per distribution, dedicated to one domain, correct ?
1
  • 1
    Your bucket needs to be either public or you need to use OAI user for CF access.
    – Marcin
    Aug 2 at 22:27
1

You are on the right track in general. Just one comment: Route53 can be omitted if your domain uses some other DNS service provider already.

Q: Does the "bucket name == domain name" requirement apply even if I use CloudFront ?

No, if you use CloudFront. The CNAME is configured separately in CloudFront.

Q: Do I need to create one bucket each for the apex domain and every subdomain ?

No, you don't need one bucket per domain/subdomain.

Why does the S3 bucket deny access ?

You should use your s3-website-us-east-1.amazonaws.com domain as the CF origin.

Is it normal for an S3 bucket to have no access policy at all ? Don't usually have "public" buckets a policy that explicitly allows access to anyone ?

If you use the bucket just to redirect traffic, no access policy should be fine.

Similar to one S3 bucket per apex / sub domain, do I also need one CloudFront distribution per apex / sub domain ?

Yes, you need one CloudFront distribution per domain/subdomain because one distribution can attach at most one ACM certificate.

If so, I guess adding *.mydomain01.com as alternate domain to the certificate (and the distribution) does not really make any sense, does it ?!? I'd also need one certificate per distribution, dedicated to one domain, correct ?

Adding the wildcard domain does make sense since the CF distribution needs to handle subdomain traffic as well.

If you have any further questions, please join the AWS Chat and @ me in the chat.

2
  • 1
    Note, AWS Console UI auto recommends using example.com.s3.us-east-1.amazonaws.com format instead of the custom example.com.s3-website-us-east-1.amazonaws.com as the article says to use as well: aws.amazon.com/premiumsupport/knowledge-center/… > Make a note of the bucket's endpoint (example.com.s3-website-us-east-1.amazonaws.com). You'll use this information to configure the origin domain name for CloudFront in the following task.
    – Tony-Caffe
    Nov 16 at 19:03
  • 1
    @Tony-Caffe Good call!
    – jellycsc
    Nov 16 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.