I have an AWS setup which involves
- A custom domain name attached too
- A cloudfront distribution with
- An API gateway as the origin in front of
- Some lambda functions that render some nextJS routes generated by
https://www.npmjs.com/package/next-aws-lambda-webpack-plugin
The provisioning code uses CDK. I've tried to remove everything that is not relevant, so the minimal example (which is unfortunately not that minimal, sorry) is at the bottom of the question.
The problem is that it seems to work, most of the time. But I seem to be getting unpredictable "CloudFront wasn't able to connect to the origin" errors and I'm really not sure why. There is some documentation on this from aws but its not really clear to me how to go about verifying which of these it is. If anyone has any suggestions it would be incredibly helpful
import { Stack, StackProps } from "aws-cdk-lib";
import * as cdk from "aws-cdk-lib";
import { Cors, LambdaIntegration, RestApi } from "aws-cdk-lib/aws-apigateway";
import { Code, LayerVersion, Runtime, Function } from "aws-cdk-lib/aws-lambda";
import { DnsValidatedCertificate } from "aws-cdk-lib/lib/aws-certificatemanager";
import { Distribution, ViewerProtocolPolicy } from "aws-cdk-lib/lib/aws-cloudfront";
import { ARecord, PublicHostedZone, RecordTarget } from "aws-cdk-lib/lib/aws-route53";
import { CloudFrontTarget } from "aws-cdk-lib/lib/aws-route53-targets";
import { Construct } from "constructs";
import { HttpOrigin } from "aws-cdk-lib/lib/aws-cloudfront-origins";
interface Props {
path1: string;
path2: string;
layerPath: string;
}
export class AppStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps & Props) {
super(scope, id, props);
const awsNextLayer = new LayerVersion(this, "aws-next-layer", {
code: Code.fromAsset(props.layerPath),
});
const functionOne = new Function(this, `function-one`, {
functionName: 'function-one',
runtime: Runtime.NODEJS_14_X,
handler: "page/handler.render",
code: Code.fromAsset(props.path1),
layers: [awsNextLayer],
});
const functionTwo = new Function(this, `function-one`, {
functionName: 'function-one',
runtime: Runtime.NODEJS_14_X,
handler: "page/handler.render",
code: Code.fromAsset(props.path1),
layers: [awsNextLayer],
});
const api = new RestApi(this, "pages-api", {
defaultCorsPreflightOptions: {
allowOrigins: Cors.ALL_ORIGINS,
},
restApiName: `api`,
});
api.root.addResource('function-one').addMethod("GET", new LambdaIntegration(functionOne));
api.root.addResource('function-two').addMethod("GET", new LambdaIntegration(functionTwo));
const domainName = `dev.app.my-domain-name.com`
const hostedZone = new PublicHostedZone(this, "HostedZone", {
zoneName: domainName,
});
const certificate = new DnsValidatedCertificate(this, "cert", {
domainName,
hostedZone,
region: "us-east-1",
});
const apiGatewayDomainName = `${api.restApiId}.execute-api.${cdk.Aws.REGION}.amazonaws.com`;
const origin = new HttpOrigin(apiGatewayDomainName, { originPath: "/prod" });
const distribution = new Distribution(this, "cdn", {
domainNames: [domainName],
defaultBehavior: {
origin,
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
},
certificate,
});
new ARecord(this, "a-record", {
zone: hostedZone,
recordName: domainName,
target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
});
}
}