Amazon Developer

as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Category SDK
MCP toolkit
Certify
Resources
Skip to main content
By default, an add-on uses API Gateway and Lambda to host the AWS architecture for the add-on. You can instead deploy the infrastructure to the topology of your choice. Choose this approach when you need to deploy on non-AWS infrastructure, integrate with existing container orchestration, or maintain a unified deployment pipeline across services. This document uses AWS Elastic Kubernetes Service (EKS) as an example, but you are not restricted to this option.

Prerequisites

Tools required:
  • Node.js 24+, npm
  • AWS CLI v2 (configured with appropriate Identity and Access Management (IAM) permissions)
  • Cloud Development Kit (CDK) CLI (npx cdk or globally installed)
  • Docker or Finch (for container image builds)
  • Access to a Cloudflare account (to configure Domain Name System (DNS) + proxy)
Knowledge assumed:
  • TypeScript / Node.js development
  • Basic AWS CDK familiarity (deploy, bootstrap)
  • Cloudflare dashboard (DNS records, Secure Sockets Layer (SSL) settings)
If you are using EKS as in this example, you also need the following:
  • Additional tools:—kubectl
  • Additional IAM permissions:—EKS, Elastic Container Registry (ECR), Virtual Private Cloud (VPC), Elastic Load Balancing (ELB) permissions on your AWS IAM role
  • Additional knowledge assumed:—Basic Kubernetes concepts (pods, deployments, services, ingress)
If you are not using EKS, refer to your platform’s documentation for equivalent requirements.

Glossary

Architecture and component model

Every add-on deployment has four logical components in the request path. The specifics of these components differ depending on whether you use the default architecture or self-hosting.

Default architecture (API Gateway + Lambda)

When using the default architecture, Alexa sends the HTTPS requests to the AWS API Gateway, which then invokes a Lambda function. Each operation the add-on can perform has handler for the Lambda entry point and operation code for the business logic. Default architecture: Alexa to API Gateway to Lambda The code provided when you create a new add-on maps to the components as shown below.

Self-hosted architecture

For the self-hosted architecture, Alexa sends the HTTPS requests to your configured Edge Proxy (such as CloudFlare), which routes to your gateway (network load balancer). Operations are then handled via smithy ServiceHandler. Self-hosted architecture: Alexa to Edge Proxy to gateway to compute The Edge Proxy, Gateway, and Compute layers are platform-specific. For the EKS example, they might look like the following. Self-hosted EKS example: Alexa to Cloudflare to NLB plus nginx to Node.js pod on EKS

Differences between default and self-hosted architectures

What stays the same across both architectures:
  • Alexa sends the same signed HTTPS request
  • verifyRequest() does the same cert-based auth
  • operations/*.ts business logic is identical
  • alexa-ai test basic auth mechanism is unchanged
What changes:
  • You add an Edge Proxy (Cloudflare) — handles TLS so origin doesn’t need a valid cert
  • Gateway changes from managed (API Gateway with OpenAPI routing) to self-managed (NLB + nginx)
  • Compute changes from serverless (one Lambda per operation) to a long-running process (one server, all operations)
  • Security boundary is unchanged — the auth mechanism (certificate verification) is identical code running in a different hosting layer. No new attack surface is introduced by the migration itself.

Make the code changes

Step 1: Create action/home-services/src/server.ts

This is the new Compute entry point — a single Node.js HTTP server that handles request authentication, operation routing, and business logic. This server replaces the Lambda handlers used in the default architecture.

Step 2: Create action/home-services/src/types.ts

This is a shared type used by server.ts and all operation files.
Update all operations/*.ts imports to use the new type. You can use the following command in your terminal to change them all at one time.

Step 3: Remove Lambda artifacts and update dependencies

The file deletions and most dependency changes apply to all platforms. The following sections call out EKS-specific dependency changes separately. Delete the old Lambda files.
Update the root package.json to remove the Lambda dependencies. For EKS, you add the new EKS dependency. Remove (all platforms):
  • @alexa-ai/category-cdk-constructs
  • @aws-smithy/server-apigateway
  • @types/aws-lambda
Add (all platforms):
  • Move @aws-smithy/server-node from devDependencies to dependencies (it is needed at runtime in the self-hosted server) "^1.0.0-alpha.5"
  • @types/node "^24.10.1" (devDependencies)
EKS-specific — add these if using EKS:
  • @aws-cdk/lambda-layer-kubectl-v32 "^2.1.0" (dependencies)
  • aws-cdk-lib → "^2.260.0" — EKS L2 constructs require ≥2.260
  • aws-cdk → "^2.260.0" — must match aws-cdk-lib
After making these updates, run npm install. Verify: At this point, npm run build should complete without errors.

Step 4: Update action/home-services/scripts/bundle/index.js

Bundle only server.ts — the single production entry point (no Lambda handlers):
Verify: npm run clean && npm run bundle should produce only action/build/dist/server.js. (The clean script should already exist in your template’s package.json.)

Step 5: Create Dockerfile (project root)

This is a container image for the Compute component.
Verify: docker build --platform linux/amd64 -t addon-service . should complete successfully.

Step 6: Provision gateway + compute infrastructure

Delete the old Lambda CDK stack:
The CDK stack uses the root package.json, tsconfig.json, and cdk.json — no separate package needed. Dependencies were already added in Step 3: Remove Lambda artifacts and update dependencies. Root cdk.json (verify it points to the correct path):
New action/infrastructure/cdk/bin/app.ts:
New action/infrastructure/cdk/lib/eks-addon-infra-stack.ts: Provisions the Gateway and Compute infrastructure: VPC, EKS cluster, NLB (restricted to Cloudflare IPs), nginx ingress controller, ECR repo, and Kubernetes deployment/service/ingress manifests.
Verify: npx cdk synth should produce a CloudFormation template without errors.

Step 7: Update config_builder.ts

Point the add-on endpoint to your Edge Proxy (Cloudflare) URL. This is the public entry point Alexa calls when sending requests to your add-on:
Timing: You can set this now with the intended URL. Traffic doesn’t flow until Cloudflare DNS is live during deployment, so there is no risk in setting it early.

Deploy your add-on

In the following steps, you deploy your add-on so that you can verify that traffic flows through the full path from Alexa -> Edge Proxy -> Gateway -> Compute.

Step 1: Build and bundle

Run the following command to build and bundle the add-on.

Step 2: Deploy infrastructure

Provision your load balancer and container runtime using your platform’s tooling. Your goal at the end of this step is a load balancer DNS hostname to use as the Cloudflare CNAME target when you configure your Edge Proxy later. For the EKS example, you do this with the following commands:
Note the outputs printed after deploy:
  • EcrRepoUri — needed for pushing container images
  • ClusterName — needed for kubectl access
  • KubeconfigCommand — run this to configure kubectl
Ensure your AWS credentials point to YOUR infrastructure account (not the CodeArtifact account). If you previously ran aws codeartifact login, verify with aws sts get-caller-identity before proceeding.

Step 3: Push the container image to registry

You can use any container registry accessible from your compute platform, such as Elastic Container Registry (ECR). The EKS example uses ECR.

Step 4: Deploy pods and start compute

This example shows using kubectl for EKS. Replace with your platform’s equivalent.

Step 5: Configure your Edge Proxy

To complete this step, you need your load balancer DNS hostname from the earlier Step 2: Deploy infrastructure. In the Cloudflare dashboard:
  1. Get your load balancer DNS hostname:
    • EKS: kubectl get svc -n ingress-nginx (copy the EXTERNAL-IP value)
    • Other platforms: retrieve from your platform’s console or CLI.
  2. Add a CNAME record: your-subdomain → <load balancer DNS hostname>.
  3. Set Proxy status: Proxied (orange cloud).
  4. Set SSL/TLS mode: Full (not Strict — the origin does not need a valid public certificate).
To verify the Edge Proxy, run the following curl command. This should return {"status":"healthy"} once DNS propagates.
If this returns 403, see Known Issues.

Step 6: Deploy add-on manifest to Alexa

Run the following command to deploy your add-on manifest to Alexa.
This registers your Cloudflare URL with Alexa. After this, Alexa routes traffic to your service.

Verify your add-on end-to-end in the Alexa simulator

Open the Alexa web simulator and invoke your add-on to confirm traffic flows through the full path (Alexa → Edge Proxy → Gateway → Compute). For details about using the web simulator, see Test with the Web Simulator. Make sure you start a new simulator session to avoid issues with caching. Older sessions might still route to a stale endpoint. Invoke operations like “get services” or “list professionals” and confirm you get valid responses from your service. For a detailed comparison, see Summary of what changes.

Summary of what changes vs. what stays the same

The following table shows the differences between the default Lambda architecture and the self-hosted solution.

Directory structure

A self-hosted add-on EKS-hosted example has the following project structure.

Known issues

Cloudflare Web Application Firewall (WAF) blocks curl/local requests

If Cloudflare WAF/bot protection is active, direct curl requests from your laptop are blocked (403). Alexa’s server-to-server traffic passes through fine. This is expected — test via the Alexa Simulator, not curl.

Running server.ts locally (CJS/ESM conflict on Node.js 24)

server.ts cannot be run directly with ts-node or tsx due to a CJS/ESM conflict in node-forge (used by @alexa-ai/category-request-authorizer). Use the bundled output for local testing:
The local/server.ts (which skips verifyRequest) still works with tsx for alexa-ai test purposes.
Last modified on August 31, 2026