If I have a static site on AWS S3 (and maybe using CloudFront) that's pretty cool, because it scales easily, and has zero-downtime deployments, because you're just updating static assets, and gets distributed to edge locations, woohoo!
But, if I want to have a contact form, or process a stripe payment. I need to run some backend code. So, how do I tell AWS that for GETs to certain routes, use S3 (or CloudFront), but if there's a form submit, direct that to this little Lambda function over here?
Could I use Route53 and direct everything at example.com/forms/... over to Lambda?
Route53 is just DNS, it doesn't do any routing based on the path. Since you are using CloudFront I believe you can use the CloudFront Behaviors feature to perform the routing you are talking about, like what is described in this blog post. Alternatively, just use a different subdomain for the dynamic parts of your web application like api.example.com for your API Gateway routes.
Related
I wonder, for example using AWS, if it was possible to detect the session of the user and send him to CDN if no session, or to the actual servers if logged in. Any ideas? I'm not too practical of CloudFront or Load balancers. Feel free to give examples using other cloud providers or Saas.
The CloudFront CDN has an integration with AWS Lambda, which allows you to intercept, inspect and modify requests at various points in their lifecycle. This is called Lambda#Edge.
You can use an Lambda#Edge function to dynamically select an origin as the source for the data based on information like the headers. AWS has published a blog post that describes this process in more details.
My requirement is to redirect url from Cloudfront. So for this I see there are possibilities to do using Lambda function as mentioned here.
My application is not hosted in S3, rather it is hosted in Apache webserver which is running on some EC2 instance.
Because redirect rules are many so I would like Lambda function to read configuration of redirect mapping from some other place but I do not know what could be the other place. I see it is possible to read either from S3 or SNS topic. Could you please suggest what is the best practice to store redirect mapping and handle redirect via Lambda?
As I understood it is not possible to do using Route53 to read mapping and then do redirect. Please correct me if I am wrong.
I am new to this and would request your expert guidance!
I think you are mistaking some concepts. If I got it right you need a CDN for an Apache server on EC2. In that case you want Cloudfront with EC2 as origin . https://aws.amazon.com/cloudfront/getting-started/EC2/
Is there a way to make sse (server sent events) work using Cloudfront?
I know they announced websockets support few years ago but I can not find any reference or cases related to using sse communication through Cloudfront.
I did a test and the client response ends with 504 Gateway Time-out after a minute approx.
Yes, you can use SSE (Server-Sent Events) with CloudFront.
There are many different ways to implement your API behind CloudFront. So, in some cases, there could be limitations. But let me describe one standard and straightforward way you could set up your application that is tested to work with SSE.
Let's say you have an EC2 instance (at least one) that is behind an ALB (Application Load Balancer). Even if you don't need more than one EC2 instance, you might need an ALB in order to use HTTPS. Even though you will need to import your TLS/SSL certificate into your CloudFront Distribution, you will also need your API to be accessible (by CloudFront itself) via HTTPS (don't forget it could be located in another continent).
In CloudFront you can create a Distribution with an Origin that basically maps https://yourapp.com/api to that ALB. Note that CloudFront also allows you to forward traffic to a different (sub)domain if that's where your API/ALB is (that setup I've also tested successfully).
Websockets works with AWS API Gateway. You can use AppSync (GraphQL) Subscriptions also. CloudFront can’t send anything himself.
AWS resources are linked with event bridge (Basically async way to trigger an event) and its stateless so it is not possible. The only way is you have to deploy your app in some sort of web container using which you can achieve your expected behaviour.
Another way is you can use AWS API Gateways's websocket open the connection (Full duplex) and back and forth transafer what ever data you want.
I have a website distributed with CloudFront, with S3 as an origin. I've written a Lambda function that takes a contact form submission and sends the email along with SES. The Lambda test out just fine : )
But, I'm clueless when it comes to routing POST requests from CloudFront to that backend Lambda function. How do I do this?
Update: Okay, I've got the API Gateway test triggering the Lambda function just fine, but I can't seem to call it from CloudFront (or rather using a curl command to my domain set up with CloudFront).
Do I need to list my domain as a custom domain in API Gateway?
If I list the path /api/* in my CloudFront Behaviors, do I have to mirror that in my API Gateway set up? So, does my API Gateway need to start with /api before I add specific resources?
Update 2 I think I needed to leave or remove the /dev off the end of the API Gateway URL. dev being my stage.
Update 3 Okay, it feels one step away now. I've got everything hooked up. The test request hits cloudfront, it forwards to api gateway, gateway calls lambda (at this point I'm shaking my head at how complicated we've made all this), and lambda sends back success or failure to api gateway, and we're peachy. Except, I get MethodNotAllowed when I do it from curl or the browser. Do I need to add an IAM role to CloudFront to access API Gateway?
Update 4 Still not working. And now, I'm back to getting my usual 404 error page that my Default Origin (S3). Seems like serverless is a fading dream.
Update 5 Trying a different approach, recommended here: https://serverfault.com/a/839368 The idea is to use API Gateway's Custom Domain name features with a subdomain like api.example.com and then use a Route53 Alias record to direct subdomain traffic to API Gateway. This could work. Then CloudFront would handle traffic to example.com and www.example.com, and API Gateway would get requests to api.example.com. Now the challenging bit is that in HTML forms the action attribute will have to go to a different subdomain. Let's see what kinds of errors and crazy behavior we get : (
First you would setup API Gateway in front of your Lambda function so it can be called via a POST request. It sounds like you may already have that part done?
Then if you want the POST to go through CloudFront you would add a second origin in CloudFront that points to your API Gateway.
This is all possible, but its tricky to configure. To help I created an open-source boilerplate app that correctly sets up:
A static site with CloudFront and S3
An API with API Gateway and Lambda
CORS between the static site and API
Optional OAuth 2.0 and JWT cookie for the static site
See this static JavaScript app for an example of a static site POSTing to an API backed by Lambda.
Depends on what you're using as your backend (which language, framework, etc.), there are different ways, but 'em all about one thing: Invoke
Kind-of the most generic call - HTTP is right there, the API call examples by language are referenced at the end of the doc.
Let say I need an API Gateway that is going to run Lambdas and I want to make the best globally distributed performing infrastructure. Also, I will use Cognito for authentication, Dynamodb, and S3 for user data and frontend statics.
My app is located at myapp.com
First the user get the static front end from the nearest location:
user ===> edge location at CloudFront <--- S3 at any region (with static front end)
After that we need to comunicate with API Gateway.
user ===> API Gateway ---> Lambda ---> S3 || Cognito || Dynamodb
API Gateway can be located in several regions, and even though is distributed with CloudFront, each endpoint is pointing to a Lambda located at a given region: Let say I deploy an API at eu-west-1. If a request is sent from USA, even if my API is on CloudFront, the Lambda it runs is located at eu-west-1, so latency will be high anyway.
To avoid that, I need to deploy another API at us-east-1 and all my Lambdas too. That API will be pointing to those Lambdas
If I deploy one API for every single region, I would need one endpoint for each one of them, and the frontend should decide which one to request. But how could we know which one is the nearest location?
The ideal scenario is a single global endpoint at api.myapp.com, which is going to go to the nearest API Gateway which runs the Lambdas located in that region too. Can I configure that using Route 53 latency routing with multiple A records pointing to each api gateway?
If this is not right way to do this, can you point me in the right direction?
AWS recently announced support for regional API endpoints using which you can achieve this.
Below is an AWS Blog which explains how to achieve this:
Building a Multi-region Serverless Application with Amazon API Gateway and AWS Lambda
Excerpt from the blog:
The default API endpoint type in API Gateway is the edge-optimized API
endpoint, which enables clients to access an API through an Amazon
CloudFront distribution. This typically improves connection time for
geographically diverse clients. By default, a custom domain name is
globally unique and the edge-optimized API endpoint would invoke a
Lambda function in a single region in the case of Lambda integration.
You can’t use this type of endpoint with a Route 53 active-active
setup and fail-over.
The new regional API endpoint in API Gateway moves the API endpoint
into the region and the custom domain name is unique per region. This
makes it possible to run a full copy of an API in each region and then
use Route 53 to use an active-active setup and failover.
Unfortunately, this is not currently possible. The primarily blocker here is CloudFront.
MikeD#AWS provides the info on their forums:
When you create a custom domain name it creates an associated CloudFront distribution for the domain name and CloudFront enforces global uniqueness on the domain name.
If a CloudFront distribution with the domain name already exists, then the CreateCloudFrontDistribution will fail and API Gateway will return an error without saving the domain name or allowing you to define it's associated API(s).
Thus, there is currently (Jun 29, 2016) no way to get API Gateway in multiple regions to handle the same domain name.
AWS has no update on providing the needful since confirming existence of an open feature request on July 4, 2016. AWS Form thread for updates
Checkout Lambda#Edge
Q: What is Lambda#Edge? Lambda#Edge allows you to run code across AWS
locations globally without provisioning or managing servers,
responding to end users at the lowest network latency. You just upload
your Node.js code to AWS Lambda and configure your function to be
triggered in response to Amazon CloudFront requests (i.e., when a
viewer request lands, when a request is forwarded to or received back
from the origin, and right before responding back to the end user).
The code is then ready to execute across AWS locations globally when a
request for content is received, and scales with the volume of
CloudFront requests globally. Learn more in our documentation.
Usecase, minimizing latency for globally distributed users
Q: When should I use Lambda#Edge? Lambda#Edge is optimized for latency
sensitive use cases where your end viewers are distributed globally.
Ideally, all the information you need to make a decision is available
at the CloudFront edge, within the function and the request. This
means that use cases where you are looking to make decisions on how to
serve content based on user characteristics (e.g., location, client
device, etc) can now be executed and served right from the edge in
Node.js-6.10 without having to be routed back to a centralized server.