wf-cdk CloudFront Infrastructure

Deploy production-ready CloudFront distributions using the wf-cdk library — a config-driven AWS CDK construct library with zero boilerplate.

Config-Driven

Write a cdk-config.js + config.json — the CLI handles everything else. No CDK app boilerplate.

Multi-Environment

Per-environment domain, bucket, and zone config via config.json — deploy to dev, qa, prod with one command.

Full Stack in One Config

S3 bucket, ACM cert, cache & response headers policies, CloudFront Function, distribution, Route 53 — all declared together.

Auto-Deploy Assets

Built-in BucketDeployment uploads dist/ to S3 and invalidates CloudFront cache on every deploy.

This page is the sample UI. It is deployed to CloudFront via the same cdk-config.js documented here. The infrastructure creates itself.

Architecture Overview

The wf-cdk CLI reads your config files at the project root, builds a CDK stack inside its own bundled app, and deploys everything.

Your Project cdk-config.js + config.json + dist/
Jenkins Pipeline NodeJSCloudfrontCDKPipeline
wf-cdk CLI bin/cdk-deploy.js
cdk-infra.js Reads config → resolves env → builds stack
L3: CloudFrontStack ACM + Policies + Functions + Distribution
L2 Constructs WFCloudFront, WFS3, WFAcm, WFRoute53Record
AWS Resources CloudFront + S3 + ACM + Route 53

Prerequisites

Node.js ≥ 18

Runtime for CDK CLI and build tools

AWS CDK CLI v2

npm install -g aws-cdk

AWS CLI v2

Configured with valid credentials for target account

CDK Bootstrap

Run cdk bootstrap aws://ACCOUNT/us-east-1 once

TARGET_ENVIRONMENT

Set to dev, qa, integration, preprod_uk, prod_uk, or prod_us

Jenkins + wf-jenkins-lib

Pipeline library @Library('wf-jenkins-lib@cdk-cfn') passes all env vars at build runtime

Project Structure

cdk-cloudfront-sample/
cdk-cloudfront-sample/
├── src/                       # Source static files (edit here)
│   ├── index.html             #   This documentation page
│   ├── styles.css             #   Stylesheet
│   └── app.js                 #   Interactive JS
├── dist/                      # Build output (npm run build → deployed to S3)
├── cdk-config.js              # CDK infrastructure config (REQUIRED)
├── config.json                # Per-environment values (REQUIRED)
├── cdk.json                   # CDK CLI context
├── package.json               # Dependencies (includes wf-cdk)
├── tsconfig.json              # TypeScript config
├── jenkins/
│   └── Jenkinsfile            # CI/CD pipeline
├── __tests__/
│   └── example.test.tsx       # Sample test
└── cdk-config.sample          # Reference sample from portal
node_modules/wf-cdk/
wf-cdk/
├── bin/
│   ├── cdk-deploy.js              # CLI entry — wraps `npx cdk`
│   └── cdk-infra.js               # CDK app — reads config, builds stack
├── lib/
│   ├── index.js / .d.ts           # Public exports (L2 constructs + types)
│   ├── constructs/
│   │   ├── L2/                    # Individual resource wrappers
│   │   │   ├── wf-cloudfront      #   WFCloudFront (Distribution + OAI)
│   │   │   ├── wf-s3              #   WFS3 (Bucket + policies)
│   │   │   ├── wf-acm             #   WFAcm (Certificate)
│   │   │   ├── wf-route53         #   WFRoute53Record (Alias A-records)
│   │   │   ├── wf-lambda          #   WFLambda (Function + IAM)
│   │   │   ├── wf-sns / wf-sqs    #   WFSNS / WFSQS
│   │   │   ├── wf-alarm / wf-dlq  #   WFAlarm / WFDLQ
│   │   │   ├── wf-iam-role        #   WFIamRole
│   │   │   ├── wf-scheduler       #   WFScheduler (EventBridge)
│   │   │   └── wf-neptune         #   WFNeptune
│   │   ├── L3/                    # Stack orchestrators
│   │   │   ├── cloudfront-stack   #   CloudFrontStack (this project uses)
│   │   │   ├── async-lambda       #   AsyncLambda (default)
│   │   │   ├── s3-stack           #   S3Stack
│   │   │   ├── acm-stack          #   AcmStack
│   │   │   └── base-l3-stack      #   BaseL3Stack (abstract)
│   │   └── WFConstruct            # Abstract base for all constructs
│   ├── types/                     # TypeScript interfaces
│   │   ├── cloudfront.d.ts        #   CloudFront types (used in config)
│   │   ├── common.d.ts            #   ConstructType enum
│   │   └── index.d.ts             #   Re-exports all types
│   ├── const/
│   │   └── defaultValue.js        #   CloudFront, S3, Lambda defaults
│   └── utils/
│       ├── deployment-environments #   Stage/env resolution
│       ├── shared-resources        #   SSM-based shared infra (hostedZoneId)
│       └── groups                  #   ServiceGroups, ProductGroups enums
├── cdk.json                       # Bundled CDK context
└── package.json                   # wf-cdk metadata

Key Project Files

Three files drive the entire infrastructure. Here is what each one does:

JS

cdk-config.js

The CDK infrastructure definition. Reads config.json for per-environment values and shared-resources for hostedZoneId. Defines ACM cert, cache/response policies, CloudFront function, distribution, and deployment.

{ }

config.json

Per-environment static values. Each key (dev, qa, etc.) maps to domainName, bucketName, and hostedZoneName. Read by cdk-config.js at deploy time.

{ }

cdk.json

CDK CLI context flags. Not used directly by wf-cdk CLI (it overrides --app), but useful for standalone cdk synth runs.

Jf

jenkins/Jenkinsfile

CI/CD pipeline using @Library('wf-jenkins-lib@cdk-cfn'). Calls NodeJSCloudfrontCDKPipeline() which sets TARGET_ENVIRONMENT, PRODUCT_GROUP, SERVICE_GROUP, and all other env vars at build runtime.

config.json

Click an environment tab to see the values that get injected into cdk-config.js at deploy time.

domainNamecdk-cfn-sample.dev.afreespace.com
bucketNamecdk-cfn-sample-afreespace-com
hostedZoneNamedev.afreespace.com
hostedZoneIdResolved from SSM (shared-resources)
domainNamecdk-cfn-sample.qa.afreespace.com
bucketNamecdk-cfn-sample-qa-afreespace-com
hostedZoneNameqa.afreespace.com
hostedZoneIdResolved from SSM (shared-resources)
domainNamecdk-cfn-sample.integration.afreespace.com
bucketNamecdk-cfn-sample-integration-afreespace-com
hostedZoneNameintegration.afreespace.com
hostedZoneIdResolved from SSM (shared-resources)
domainNamecdk-cfn-sample.preprod.afreespace.com
bucketNamecdk-cfn-sample-preprod-afreespace-com
hostedZoneNamepreprod.afreespace.com
hostedZoneIdResolved from SSM (shared-resources)
domainNamecdk-cfn-sample.afreespace.com
bucketNamecdk-cfn-sample-prod-uk-afreespace-com
hostedZoneNameafreespace.com
hostedZoneIdResolved from SSM (shared-resources)
domainNamecdk-cfn-sample.us.afreespace.com
bucketNamecdk-cfn-sample-prod-us-afreespace-com
hostedZoneNameus.afreespace.com
hostedZoneIdResolved from SSM (shared-resources)
View full config.json source
config.json
{
  "dev": {
    "domainName": "cdk-cfn-sample.dev.afreespace.com",
    "bucketName": "cdk-cfn-sample-afreespace-com",
    "hostedZoneName": "dev.afreespace.com"
  },
  "qa": {
    "domainName": "cdk-cfn-sample.qa.afreespace.com",
    "bucketName": "cdk-cfn-sample-qa-afreespace-com",
    "hostedZoneName": "qa.afreespace.com"
  },
  "integration": {
    "domainName": "cdk-cfn-sample.integration.afreespace.com",
    "bucketName": "cdk-cfn-sample-integration-afreespace-com",
    "hostedZoneName": "integration.afreespace.com"
  },
  "preprod_uk": {
    "domainName": "cdk-cfn-sample.preprod.afreespace.com",
    "bucketName": "cdk-cfn-sample-preprod-afreespace-com",
    "hostedZoneName": "preprod.afreespace.com"
  },
  "prod_uk": {
    "domainName": "cdk-cfn-sample.afreespace.com",
    "bucketName": "cdk-cfn-sample-prod-uk-afreespace-com",
    "hostedZoneName": "afreespace.com"
  },
  "prod_us": {
    "domainName": "cdk-cfn-sample.us.afreespace.com",
    "bucketName": "cdk-cfn-sample-prod-us-afreespace-com",
    "hostedZoneName": "us.afreespace.com"
  }
}

cdk-config.js

The actual config file used by this project. Annotated inline — click sections to expand.

Imports & Environment Resolution
cdk-config.js — lines 1-32
const cloudfront = require('aws-cdk-lib/aws-cloudfront');
const { ConstructType } = require('wf-cdk/lib/types');
const { WFCloudFrontManagedPolicies } = require('wf-cdk/lib/types/cloudfront');
const { ProductGroups, ServiceGroups } = require('wf-cdk/lib/utils/groups');
const { getSharedResources } = require('wf-cdk/lib/utils/shared-resources');
const { getStageForEnvironment } = require('wf-cdk/lib/utils/deployment-environments');

const shared = getSharedResources();
const stage = getStageForEnvironment().toString();

// Per-environment config
const targetEnv = process.env.TARGET_ENVIRONMENT || 'dev';
const envConfig = require('./config.json');

if (!envConfig[targetEnv]) {
  throw new Error(
    `No config entry for TARGET_ENVIRONMENT="${targetEnv}".`
    + ` Valid: ${Object.keys(envConfig).join(', ')}`,
  );
}

const env = { ...envConfig[targetEnv], hostedZoneId: shared.hostedZoneId };
How it works: TARGET_ENVIRONMENT is set by Jenkins at build runtime (via NodeJSCloudfrontCDKPipeline). getSharedResources() reads SSM parameters to get shared infra values like hostedZoneId. getStageForEnvironment() maps the env to a stage name (e.g. prod_ukprod). The result is merged with static values from config.json.
Security Headers
cdk-config.js — SHARED_SECURITY_HEADERS
const SHARED_SECURITY_HEADERS = {
  strictTransportSecurity: {
    accessControlMaxAgeSec: 63072000,   // 2 years
    includeSubdomains: true,
    preload: true,
    override: true,
  },
  contentTypeOptions: { override: true },
  frameOptions: { frameOption: 'DENY', override: true },
  xssProtection: { protection: true, modeBlock: true, override: true },
  referrerPolicy: {
    referrerPolicy: 'strict-origin-when-cross-origin',
    override: true,
  },
};
Top-Level Config: service, groups, certificate, hostedZone
cdk-config.js — cdkConfig (top-level)
const cdkConfig = {
  service: 'cdk-cfn-sample',
  ServiceGroup: ServiceGroups.INFRA,
  ProductGroup: ProductGroups.DEVOPS,
  constructType: ConstructType.CLOUDFRONT_STACK,

  certificate: {
    certificateName: `${stage}-cdk-cfn-sample-cert`,
    domainName: env.domainName,
    hostedZoneId: env.hostedZoneId,
    hostedZoneName: env.hostedZoneName,
  },

  hostedZone: {
    hostedZoneId: env.hostedZoneId,
    zoneName: env.hostedZoneName,
  },
  // ... cachePolicies, responseHeadersPolicies, etc.
};
Cache Policy + Response Headers Policy
cdk-config.js — policies
  cachePolicies: [
    {
      name: `cdk-${stage}-cfn-sample-edge-7d`,
      comment: '7-day edge cache for static assets',
      defaultTtl: 604800,
      maxTtl: 604800,
      minTtl: 0,
      enableAcceptEncodingBrotli: true,
      enableAcceptEncodingGzip: true,
    },
  ],

  responseHeadersPolicies: [
    {
      name: `cdk-${stage}-cfn-sample-browser-60s`,
      comment: '60s browser cache with security headers',
      corsConfig: {
        accessControlAllowOrigins: ['*'],
        accessControlAllowHeaders: ['*'],
        accessControlAllowMethods: ['GET', 'HEAD', 'OPTIONS'],
        accessControlAllowCredentials: false,
        originOverride: true,
      },
      customHeaders: [
        { header: 'Cache-Control', value: 'public, max-age=60, stale-while-revalidate=300', override: true },
        { header: 'Server', value: 'null', override: true },
      ],
      securityHeaders: SHARED_SECURITY_HEADERS,
    },
  ],
CloudFront Function (SPA Routing)
cdk-config.js — cloudfrontFunctions
  cloudfrontFunctions: [
    {
      name: `cdk-${stage}-cfn-sample-spa-routing`,
      comment: 'SPA routing - rewrite extensionless URIs to /index.html',
      runtime: 'cloudfront-js-1.0',
      code: `function handler(event) {
    var request = event.request;
    var uri = request.uri;
    var hasFileExtension = /\\.[a-zA-Z0-9]+$/.test(uri);
    if (!hasFileExtension) {
        request.uri = '/index.html';
    }
    return request;
}`,
    },
  ],
SPA routing: Any request without a file extension (e.g. /about, /dashboard) is rewritten to /index.html at the edge, so the single-page app's client-side router handles it. Requests with extensions (e.g. /styles.css, /app.js) pass through unchanged.
Distribution + Deployment
cdk-config.js — distributions
  distributions: [
    {
      distributionName: 'cdk-cfn-sample',
      origin: {
        type: 's3',
        createBucket: true,
        bucketName: env.bucketName,
      },
      aliases: [env.domainName],
      comment: 'CDK CloudFront sample distribution',
      defaultRootObject: 'index.html',
      httpVersion: cloudfront.HttpVersion.HTTP2,
      enableIpv6: false,
      priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
      minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
      createDnsRecords: true,

      defaultBehavior: {
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
        cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
        compress: true,
        cachePolicyName: `cdk-${stage}-cfn-sample-edge-7d`,
        originRequestPolicyId: WFCloudFrontManagedPolicies.originRequest.CORS_S3_ORIGIN,
        responseHeadersPolicyName: `cdk-${stage}-cfn-sample-browser-60s`,
        functionAssociations: [
          {
            eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
            functionName: `cdk-${stage}-cfn-sample-spa-routing`,
          },
        ],
      },

      errorResponses: [
        { httpStatus: 403, responsePagePath: '/index.html', responseHttpStatus: 200, ttl: 60 },
        { httpStatus: 404, responsePagePath: '/index.html', responseHttpStatus: 200, ttl: 60 },
      ],

      deployment: {
        sourceDir: './dist',
        invalidationPaths: ['/*'],
      },
    },
  ],

L2 Constructs — Resource Wrappers

Exported from the package entrypoint (require('wf-cdk')). Each wraps one AWS resource.

WFCloudFront

CloudFront Distribution with S3 or custom origin, OAI, and CfnOutputs.

cloudfronts3

WFS3

S3 bucket with encryption, block public access, versioning. Supports fromBucketName().

s3

WFAcm

ACM certificate — create with DNS validation or import by ARN.

acmroute53

WFRoute53Record

Route 53 alias A-records. forDistribution() helper for CF aliases.

route53

WFLambda

Lambda with IAM role, esbuild bundling, event sources, VPC support.

lambdaiam

WFSQS

SQS queue + DLQ, SNS subscriptions, CloudWatch alarms.

sqssns

WFSNS

SNS topic with alarms and subscription management.

sns

WFAlarm

CloudWatch alarm with severity mapping (INFO/MAJOR).

cloudwatch

WFIamRole

IAM role with inline/managed policies and static factories.

iam

WFScheduler

EventBridge rule — everyHours(), everyDays() helpers + Lambda target.

eventbridge

WFDLQ

Dead Letter Queue with associated CloudWatch alarms.

sqscloudwatch

WFNeptune

Neptune cluster with VPC, security groups, IAM, optional S3 bulk-load.

neptunevpc

L3 Constructs — Stack Orchestrators

Used by the CLI via constructType in your config. Each composes multiple L2 constructs.

constructTypeClassResources Created
CloudFrontStackCloudFrontStackACM certs, cache policies, response header policies, CF functions, CloudFront distributions, S3 buckets, Route 53 records, BucketDeployment + invalidation
AsyncLambdaAsyncLambdaLambda functions, SQS queues, SNS topics, DLQs, EventBridge schedulers
S3StackS3StackOne or more WFS3 buckets
AcmStackAcmStackMultiple WFAcm certificates
NeptuneDatabaseNeptuneDatabaseNeptune cluster, VPC config, security groups, SSM parameters
IoTLoRaWANStackIoTLoRaWANStackIoT device/service profiles, topic rules, destinations, SSM outputs
Default is AsyncLambda. For CloudFront, you must set constructType: ConstructType.CLOUDFRONT_STACK (or the string 'CloudFrontStack'). The CLI forces us-east-1 for CloudFront stacks.

CloudFront Type Definitions

Exported from wf-cdk/lib/types/cloudfront. These define what you can put in cdk-config.js.

CloudFrontStackProps (top-level)
TypeScript
interface CloudFrontStackProps {
  service: string;
  ServiceGroup: ServiceGroups;
  ProductGroup: ProductGroups;
  constructType?: ConstructType;            // 'CloudFrontStack'
  certificate?: WFAcmCertificateConfig;
  hostedZone?: WFRoute53HostedZoneConfig;
  cachePolicies?: WFCloudFrontCachePolicyConfig[];
  responseHeadersPolicies?: WFCloudFrontResponseHeadersPolicyConfig[];
  cloudfrontFunctions?: WFCloudFrontFunctionConfig[];
  distributions: WFCloudFrontDistributionConfig[];  // REQUIRED
  tags?: EnvironmentVariable;
}
WFCloudFrontDistributionConfig
TypeScript
interface WFCloudFrontDistributionConfig {
  distributionName: string;
  origin: WFCloudFrontS3Origin | WFCloudFrontCustomOrigin;
  aliases?: string[];
  certificateArn?: string;
  defaultRootObject?: string;       // Default: 'index.html'
  enabled?: boolean;
  httpVersion?: HttpVersion;
  enableIpv6?: boolean;
  priceClass?: PriceClass;
  minimumProtocolVersion?: SecurityPolicyProtocol;
  comment?: string;
  webAclId?: string;
  defaultBehavior?: { /* see below */ };
  cacheBehaviors?: WFCloudFrontCacheBehavior[];
  errorResponses?: WFCloudFrontErrorResponse[];
  disableDefaultErrorResponses?: boolean;
  createDnsRecords?: boolean;
  deployment?: WFCloudFrontDeploymentConfig;
}
Origin Types (S3 + Custom)
TypeScript
interface WFCloudFrontS3Origin {
  type: 's3';
  bucketName?: string;
  bucketArn?: string;
  bucketRef?: s3.IBucket;
  createBucket?: boolean;
  bucketConfig?: WFS3BucketConfig;
  accessType?: 'oai' | 'oac';
}

interface WFCloudFrontCustomOrigin {
  type: 'custom';
  domainName: string;
  httpPort?: number;
  httpsPort?: number;
  protocolPolicy?: OriginProtocolPolicy;
}

interface WFCloudFrontDeploymentConfig {
  sourceDir: string;           // e.g. './dist'
  invalidationPaths?: string[];
  exclude?: string[];
  prune?: boolean;
}
Cache, Response Headers & Function Config
TypeScript
interface WFCloudFrontCachePolicyConfig {
  name: string;
  defaultTtl?: number;  maxTtl?: number;  minTtl?: number;
  enableAcceptEncodingBrotli?: boolean;
  enableAcceptEncodingGzip?: boolean;
  cookieBehavior?: 'none' | 'whitelist' | 'allExcept' | 'all';
  queryStringBehavior?: 'none' | 'whitelist' | 'allExcept' | 'all';
}

interface WFCloudFrontResponseHeadersPolicyConfig {
  name: string;
  corsConfig?: { accessControlAllowOrigins, allowHeaders, allowMethods, ... };
  securityHeaders?: { strictTransportSecurity, contentTypeOptions, frameOptions, xssProtection, ... };
  customHeaders?: { header: string; value: string; override: boolean; }[];
  removeHeaders?: string[];
}

interface WFCloudFrontFunctionConfig {
  name: string;
  runtime?: 'cloudfront-js-1.0' | 'cloudfront-js-2.0';
  code: string;             // Inline function source
  autoPublish?: boolean;
}
Managed Policy IDs
WFCloudFrontManagedPolicies
const WFCloudFrontManagedPolicies = {
  cache: {
    CACHING_DISABLED:              '4135ea2d-6df8-44a3-9df3-4b5a84be39ad',
    CACHING_OPTIMIZED:             '658327ea-f89d-4fab-a63d-7e88639e58f6',
    CACHING_OPTIMIZED_UNCOMPRESSED:'b2884449-e4de-46a7-ac36-70bc7f1ddd6d',
  },
  originRequest: {
    CORS_S3_ORIGIN: '88a5eaf4-2fd4-4709-b370-b4c650ea3fcf',
    ALL_VIEWER:     '216adef6-5c7f-47e4-b989-5492eafa07d3',
  },
};

Environment Variables

VariableRequiredDescription
TARGET_ENVIRONMENTRequireddev, qa, integration, preprod_uk, prod_uk, prod_us
PRODUCT_GROUPRequiredProduct group enum — e.g. DEVOPS, PF (Platform)
SERVICE_GROUPRequiredService group enum — e.g. INFRA, CDK
CDK_DEPLOY_ACCOUNTOptionalAWS account ID. Falls back to CDK_DEFAULT_ACCOUNT
CDK_DEPLOY_REGIONOptionalAWS region. CloudFront stacks are forced to us-east-1
ARTIFACTSOptionalS3 bucket for assets. Enables custom synthesizer with BUILD_NUMBER
BUILD_NUMBEROptionalCI build number for asset prefix
SOURCE_DIROptionalOverride deployment.sourceDir
INVALIDATION_PATHSOptionalComma-separated paths — overrides config
No .env file needed. All environment variables are injected by the Jenkins pipeline at build runtime via NodeJSCloudfrontCDKPipeline() from @Library('wf-jenkins-lib@cdk-cfn'). For local testing, export them in your shell: export TARGET_ENVIRONMENT=dev.

CLI Usage

The wf-cdk binary wraps AWS CDK CLI. It auto-appends --all and --require-approval never.

Commands
# Deploy all stacks
TARGET_ENVIRONMENT=dev npx wf-cdk deploy

# Synthesize CloudFormation templates (dry run)
TARGET_ENVIRONMENT=dev npx wf-cdk synth

# Preview changes against deployed
TARGET_ENVIRONMENT=dev npx wf-cdk diff

# List stacks
npx wf-cdk list

# Destroy
TARGET_ENVIRONMENT=dev npx wf-cdk destroy

# Or use npm scripts (set TARGET_ENVIRONMENT first)
npm run cdk:deploy
npm run cdk:synth
npm run cdk:diff

# In Jenkins, env vars are set by the pipeline automatically:
#   NodeJSCloudfrontCDKPipeline(additionalChoiceParam, "20", true)

CLI Execution Flow

1 wf-cdk deploy → parses args, spawns npx cdk deploy --app "node cdk-infra.js"
2 cdk-infra.js reads env vars (set by Jenkins at build runtime)
3 Runs optional pre-deployment.ts hook (if exists)
4 Reads cdk-config.js (which loads config.json + shared-resources)
5 Creates CDK App & Stack (region forced to us-east-1 for CloudFront)
6 Instantiates CloudFrontStack with merged config
7 CDK synthesizes CloudFormation → deploys → uploads dist/ → invalidates cache
8 Post-deploy: merges *.assets.json → uploads manifest.json to S3

Step-by-Step Deployment

1

Install dependencies

Terminal
npm install
2

Set environment (Jenkins does this automatically)

Terminal (local only)
export TARGET_ENVIRONMENT=dev
export PRODUCT_GROUP=DEVOPS
export SERVICE_GROUP=INFRA

In CI, the Jenkins pipeline (NodeJSCloudfrontCDKPipeline) sets all required env vars automatically.

3

Bootstrap CDK (first time only)

Terminal
npx cdk bootstrap aws://ACCOUNT_ID/us-east-1
4

Preview (optional)

Terminal
npm run cdk:synth   # generates CloudFormation in cdk.out/
npm run cdk:diff    # shows changes vs deployed stack
5

Deploy

Terminal
npm run cdk:deploy

Creates S3 bucket (cdk-cfn-sample-afreespace-com), uploads dist/, provisions ACM cert + CloudFront distribution at cdk-cfn-sample.dev.afreespace.com, creates Route 53 alias, and invalidates the cache.

Built-in Defaults

Applied by WFCloudFront when not overridden in config:

PropertyDefault
defaultRootObjectindex.html
httpVersionhttp2
enableIpv6false
priceClassPriceClass_All
minimumProtocolVersionTLSv1.2_2021
compresstrue
viewerProtocolPolicyredirect-to-https

SPA Error Responses (auto-applied)

Unless disableDefaultErrorResponses: true:

HTTP StatusResponse PathResponse CodeTTL
403/index.html20010s
404/index.html20010s
Note: This project overrides error TTL to 60s in cdk-config.js for longer edge caching.