Closed simonw closed 1 year ago
I'm going to first try setting up a CloudFront distribution. If I can get that running in front of a Lambda URL I'll have solved half the problem - the other half will be figuring out how to point a custom domain at CloudFront.
Some useful docs:
I'm going to skim through and make notes on the whole Amazon CloudFront developer guide: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html
It's basically a caching CDN like Fastly. You don't pay for transfer between your Amazon-hosted application servers and CloudFront, but you do pay for bandwidth served between CloudFront and end users.
Optionally, you can configure your origin server to add headers to the files, to indicate how long you want the files to stay in the cache in CloudFront edge locations. By default, each file stays in an edge location for 24 hours before it expires.
Sounds like max-age
or s-maxage
is pretty important then!
CloudFront can also run "Lambda@Edge" functions, but these can currently only be written in JavaScript.
You can chose a cheaper plan that doesn't have POP locations in some countries: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PriceClass.html
https://fnkvspusjrl5dxytaxnuwidxem0hverw.lambda-url.us-east-1.on.aws/ is the function URL I want to use.
https://d81numqdze872.cloudfront.net/ is not working yet.
OK it works now.
Hitting the same page twice with curl
:
~ % time curl 'https://d81numqdze872.cloudfront.net/fixtures/compound_three_primary_keys'
...
</html>curl 0.02s user 0.02s system 4% cpu 0.764 total
~ % time curl 'https://d81numqdze872.cloudfront.net/fixtures/compound_three_primary_keys'
...
</html>curl 0.02s user 0.01s system 26% cpu 0.117 total
I don't think querystring parameters are being passed through correctly.
https://d81numqdze872.cloudfront.net/fixtures/no_primary_key?_facet=a ignores the facet request.
But https://fnkvspusjrl5dxytaxnuwidxem0hverw.lambda-url.us-east-1.on.aws/fixtures/no_primary_key?_facet=a works correctly.
I think I want "Forward all, cache based on all" for query strings, somewhere under "Cache behavior settings".
Looks like that's hidden away under "legacy cache settings":
That seemed to take effect pretty fast, https://d81numqdze872.cloudfront.net/fixtures/sortable?_facet=pk2 works now.
Got to that edit interface by clicking:
I can't figure out how to enable the x-cache
header for Cloudfront.
Weird. I'm getting those headers now!
I tried adding and then removing a Response Headers Policy to the distribution's behaviour, but I don't know if that made a difference here or not. Maybe it was working anyway?
Janky video trying to show where I found that option:
OK, I have that header now and it seems to confirm my 5s TTL is working as it should
Next job: point a custom domain at https://d81numqdze872.cloudfront.net/ !
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html shows how to do that for HTTP (I'll add HTTPS later, following https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https-alternate-domain-names.html ):
- Sign in to the AWS Management Console and open the CloudFront console at https://console.aws.amazon.com/cloudfront/v3/home
- Choose the ID for the distribution that you want to update.
- On the General tab, choose Edit.
- Update the following values: Alternate Domain Names (CNAMEs) Add your alternate domain names. Separate domain names with commas, or type each domain name on a new line.
Now in my DNS provider:
Use the method provided by your DNS service provider to add a CNAME record for your domain. This new CNAME record will redirect DNS queries from your alternate domain name (for example, www.example.com) to the CloudFront domain name for your distribution (for example, d111111abcdef8.cloudfront.net). For more information, see the documentation provided by your DNS service provider.
Did this in Vercel:
Just noticed I got this error in AWS when I tried to save that though:
Decided to click "Request certificate" and see what happens:
Sent me to https://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/request
Looks like this has the validation bit: https://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/98a4b28c-d7d1-4ad6-ae28-4db269e03ccc
In Vercel:
A few seconds later:
Annoyingly that certificate is not shown in this drop-down menu:
Maybe because this now says "Failed": https://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/98a4b28c-d7d1-4ad6-ae28-4db269e03ccc
I'm deleting the certificate and trying again.
I think I didn't put the right values into Vercel.
Trying with the full copy of these:
_9150f9c8c1bc531c257114dc32c51bff.lambda-demo.datasette.io.
_fd09657d57266a937c50b8b626fe9a4d.gbycpywhzv.acm-validations.aws.
That came back "Failed" too.
I'm going to try email validation.
Looks like it emailed these addresses:
I don't think I have email configured for that domain at all, so this is not going to work.
https://docs.aws.amazon.com/acm/latest/userguide/dns-validation.html says:
If your DNS provider does not support CNAME values with a leading underscore, see Troubleshoot DNS Validation Problems.
https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-DNS-validation.html says:
If your DNS provider prohibits leading underscores in CNAME values, you can remove the underscore from the ACM-provided value and validate your domain without it. For example, the CNAME value _x2.acm-validations.aws can be changed to x2.acm-validations.aws for validation purposes. However, the CNAME name parameter must always begin with a leading underscore.
I think Vercel may have stripped the trailing .
:
Yeah even if I try and add that back in again Vercel saves it without the trailing .
.
https://dev.to/wulfmann/generating-acm-certificates-for-a-vercel-managed-domain-gk5 says:
AWS provides documentation on how to configure a CAA record to allow ACM to generate certs. We need to add an extra record in Vercel:
CAA 0 issue "amazon.com"
Request a new ACM cert and this time it succeeds!
I think that worked! Created a new certificate and went through the DNS validation process and:
ARN of the certificate is:
arn:aws:acm:us-east-1:462092780466:certificate/66e7114b-6215-4c66-935c-397d60986b9a
And now it shows up here:
Selected it and now this looks promising:
http://lambda-demo.datasette.io/ (HTTP) shows this:
Maybe that will fix itself in a few seconds/minutes?
~ % curl -i 'http://lambda-demo.datasette.io/'
HTTP/1.1 403 Forbidden
Server: CloudFront
Date: Sun, 02 Oct 2022 22:19:51 GMT
Content-Type: text/html
Content-Length: 915
Connection: keep-alive
X-Cache: Error from cloudfront
Via: 1.1 549a5eaa264d3b997d6acfdba72f56d0.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: SFO5-P1
X-Amz-Cf-Id: SC5jwUCUsNhyLxpWaw4S9XuNy8tIYnmYyOGf3g4uBAOjzfkgUteS3A==
But https://d81numqdze872.cloudfront.net/ still works.
Will https://lambda-demo.datasette.io/ work soon? Is the deploy still going out?
That suggests it is still serving the *.cloudfront.net
certificate, not my now lambda-demo.datasette.io
certificate.
Maybe this should be filled in?
Editing here:
And it works!!
So I did it. I managed to point a custom domain and certificate at a Lambda Function URL!
It was really fiddly, and took a lot of steps. And I've so far only done it through the console.
I wonder if it's possible to get a wildcard certificate for a domain such that you don't have to do all of this junk for each new subdomain you want to use?
The HTTP version at http://lambda-demo.datasette.io/ doesn't redirect to HTTPS and it should do.
Trying these options:
... and about 15 seconds later the redirect works now.
Here's a bug:
https://lambda-demo.datasette.io/fixtures/facetable
Click a suggested facet link and:
It's bumped to the Lambda Function URL.
I bet I can fix that with https://datasette.io/plugins/datasette-x-forwarded-host
Maybe by re-deploying that function again, if I can remember how I did that?
[This issue thread provides a blow-by-blow account of how I figured out the way to serve an AWS Lambda function from a custom domain, using CloudFront and ACM]
I think Cloudfront is the way to do this:
My previous notes on how I shipped the Lambda Function URL are here: https://til.simonwillison.net/awslambda/asgi-mangum