CDN Deployment
The CdnDeployment construct automates the configuration of Statista's internal
CDN to route traffic to your application. It creates a custom CloudFormation
resource that writes routing configuration to AWS Systems Manager Parameter
Store in the CDN account, enabling path-based traffic routing from the CDN to
your application.
[!NOTE] This construct was previously available in
@pit-shared/remix-tools/cdkbut has been moved to@pit-shared/cdk/cdn-deploymentfor better dependency management. The old import path is still supported but deprecated.
Requirements
- Your application must implement the
CdnDeploymentTargetinterface (provide a URL and CDN secret) - The application must validate the CDN secret on all incoming requests to ensure traffic originates from the CDN
- Must specify the target environment (
production,prod, orstage) - Must provide a
basePathfor routing (e.g.,/my-app)
Basic Usage Example
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
declare const scope: import('aws-cdk-lib').Stack
new CdnDeployment(scope, 'cdn', {
environmentName: 'prod',
basePath: '/my-app',
app: {
url: 'https://my-app.example.com',
cdnSecret: 'shared-secret-value',
},
})
Usage with Custom App Paths
If you only want specific paths under your basePath to be routed (rather than
all paths), use the appPaths property. The basePath is still required but
won't be used as a routing entry when appPaths is specified.
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
declare const scope: import('aws-cdk-lib').Stack
new CdnDeployment(scope, 'cdn', {
environmentName: 'prod',
basePath: '/my-app',
appPaths: ['/my-app/api', '/my-app/public', '/my-app/assets'],
app: {
url: 'https://my-app.example.com',
cdnSecret: 'shared-secret-value',
},
})
Usage with Datadog Integration
Connect the CDN deployment with Datadog to monitor the custom resource Lambda function.
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
import { Datadog } from '@pit-shared/cdk/datadog'
declare const scope: import('aws-cdk-lib').Stack
const datadog = new Datadog(scope, 'datadog', {
apiKey: 'api-key',
env: 'prod',
service: 'my-app',
team: 'architects',
cluster: 'other',
costCategory: 'operational',
repositoryUrl: 'github.com/my-org/my-repo',
version: '1.0.0',
})
new CdnDeployment(scope, 'cdn', {
environmentName: 'prod',
basePath: '/my-app',
datadog,
app: {
url: 'https://my-app.example.com',
cdnSecret: 'shared-secret-value',
},
})
Usage in default Environments
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
declare const scope: import('aws-cdk-lib').Stack
new CdnDeployment(scope, 'cdn', {
environmentName: 'stage',
basePath: '/my-app',
app: {
url: 'https://my-app-stage.example.com',
cdnSecret: 'shared-secret-value',
},
})
Integration with RemixApp
RemixApp implements the CdnDeploymentTarget interface, so you can pass it
directly to CdnDeployment.
import { RemixApp } from '@pit-shared/remix-tools/cdk'
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
declare const scope: import('aws-cdk-lib').Stack
const app = new RemixApp(scope, 'remix', {
root: '.',
fargate: {
dns: {
domainName: 'example.com',
hostedZoneId: '1234',
zoneName: 'example.com',
skipCName: true,
},
network: {
vpcId: 'vpc-1234567890abcdef0',
internetGatewayId: 'igw-1234',
},
},
})
new CdnDeployment(scope, 'cdn', {
environmentName: 'prod',
basePath: '/my-remix-app',
app: app,
})
Integration with FargateApp
FargateApp provides an asCdnTarget() method to enable CDN deployment
integration.
[!NOTE] FargateApp requires calling
.asCdnTarget()to use withCdnDeployment, unlikeRemixAppwhich can be passed directly. This is becauseFargateAppis a general-purpose construct that doesn't always require CDN integration.
import { FargateApp } from '@pit-shared/cdk/fargate'
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'
import * as ecs from 'aws-cdk-lib/aws-ecs'
declare const scope: import('aws-cdk-lib').Stack
class MyFargateApp extends FargateApp {
protected getContainerImage(): ecs.ContainerImage {
return ecs.ContainerImage.fromAsset('.')
}
}
const app = new MyFargateApp(scope, 'fargate', {
dns: {
domainName: 'example.com',
hostedZoneId: '1234',
zoneName: 'example.com',
},
network: {
vpcId: 'vpc-1234567890abcdef0',
internetGatewayId: 'igw-1234',
},
})
new CdnDeployment(scope, 'cdn', {
environmentName: 'prod',
basePath: '/my-fargate-app',
app: app.asCdnTarget(),
})
API
CdnDeploymentProps
/**
* The app to publish.
*
* @see {CdnDeploymentTarget}
*/
app: CdnDeploymentTarget
/**
* The applications basePath (e.g. /outlook)
*/
basePath: `/${string}`
/**
* The applications paths to register (e.g. /outlook).
*
* These app paths are required if not all paths under the basePath should
* be routed into the application. Still the `basePath` has to be
* configured.
* If the app paths are set, the `basePath` is not used as a routing entry.
*/
appPaths?: `/${string}`[]
/**
* This prop could be used to force update deployment data.
* If it's not set it defaults to 0. Whenever the version changes,
* a deployment is enforced. So set it to one and increment to
* force updates.
*
* This parameter should rarely be necessary to use. Use with caution.
*
* @default 0
*/
version?: number
/**
* The log group to use, otherwise a new one is created.
*/
logGroup?: logs.ILogGroup
/**
* Integrate this custom resource with datadog
*/
datadog?: Datadog
CdnDeploymentTarget
/**
* URL to route requests to.
*/
url: string
/**
* Secret shared between the CDN and the application.
*/
cdnSecret: string
Migration Guide
If you're currently importing from @pit-shared/remix-tools/cdk, update your
imports:
// ❌ Deprecated (still works)
import { CdnDeployment } from '@pit-shared/remix-tools/cdk'
// ✅ Current
import { CdnDeployment } from '@pit-shared/cdk/cdn-deployment'