{"id":29072724,"url":"https://github.com/thunder-so/cdk-webservice","last_synced_at":"2026-04-01T17:17:39.478Z","repository":{"id":300689406,"uuid":"1006398767","full_name":"thunder-so/cdk-webservice","owner":"thunder-so","description":"Deploy containerized web services on AWS Fargate with an Application Load Balancer, using AWS CDK. ","archived":false,"fork":false,"pushed_at":"2025-12-20T01:40:56.000Z","size":203,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-28T01:30:17.176Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thunder-so.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-22T07:12:49.000Z","updated_at":"2025-12-20T01:40:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"7aca38f8-9ffc-420f-a182-c70d682f86c0","html_url":"https://github.com/thunder-so/cdk-webservice","commit_stats":null,"previous_names":["thunder-so/cdk-webservice"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/thunder-so/cdk-webservice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thunder-so%2Fcdk-webservice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thunder-so%2Fcdk-webservice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thunder-so%2Fcdk-webservice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thunder-so%2Fcdk-webservice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thunder-so","download_url":"https://codeload.github.com/thunder-so/cdk-webservice/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thunder-so%2Fcdk-webservice/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-27T14:08:31.326Z","updated_at":"2026-04-01T17:17:39.447Z","avatar_url":"https://github.com/thunder-so.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CDK Web Service\r\n\r\n\u003cp\u003e\r\n    \u003ca href=\"https://github.com/thunder-so/cdk-webservice/actions/workflows/publish.yml\"\u003e\u003cimg alt=\"Build\" src=\"https://img.shields.io/github/actions/workflow/status/thunder-so/cdk-webservice/publish.yml?logo=github\" /\u003e\u003c/a\u003e\r\n    \u003ca href=\"https://www.npmjs.com/package/@thunderso/cdk-webservice\"\u003e\u003cimg alt=\"Version\" src=\"https://img.shields.io/npm/v/@thunderso/cdk-webservice.svg\" /\u003e\u003c/a\u003e\r\n    \u003ca href=\"https://www.npmjs.com/package/@thunderso/cdk-webservice\"\u003e\u003cimg alt=\"Downloads\" src=\"https://img.shields.io/npm/dm/@thunderso/cdk-webservice.svg\"\u003e\u003c/a\u003e\r\n    \u003ca href=\"https://www.npmjs.com/package/@thunderso/cdk-webservice\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/npm/l/@thunderso/cdk-webservice.svg\" /\u003e\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\nDeploy containerized web services on AWS Fargate with an Application Load Balancer, using AWS CDK. \r\n\r\nSupports custom domains, environment variables, secrets, and CI/CD with GitHub Actions.\r\n\r\n\r\n## Features\r\n\r\n- Deploy any web service as a Docker container to [AWS Fargate](https://aws.amazon.com/fargate/)\r\n- Automatic [VPC](https://aws.amazon.com/vpc/) and [ECS Cluster](https://aws.amazon.com/ecs/) creation\r\n- [Application Load Balancer (ALB)](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/) with public DNS\r\n- Environment variables and [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) integration\r\n- Custom domain and SSL via [Route53](https://aws.amazon.com/route53/) and [Certificate Manager](https://aws.amazon.com/certificate-manager/)\r\n- CI/CD ready with [Github Actions](https://docs.github.com/en/actions)\r\n\r\n\r\n## Prerequisites\r\n\r\nYou need an [AWS account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/) to create and deploy the required resources for the site on AWS.\r\n\r\nBefore you begin, make sure you have the following:\r\n  - Node.js and npm: Ensure you have Node.js (v20 or later) and npm installed.\r\n  - AWS CLI: Install and configure the AWS Command Line Interface.\r\n\r\n  - AWS CDK: Install the AWS CDK globally\r\n```\r\nnpm install -g aws-cdk\r\n```\r\n\r\n  - Before deploying, bootstrap your AWS environment:\r\n```\r\ncdk bootstrap aws://your-aws-account-id/us-east-1\r\n```\r\n\r\nThis package uses the `npm` package manager and is an ES6+ Module.\r\n\r\n# Nixpacks Integration\r\n\r\nYou can use [Nixpacks](https://nixpacks.com/) to build your container images automatically. To enable Nixpacks, set `buildProps.buildSystem` to `'Nixpacks'` in your `WebServiceProps` configuration:\r\n\r\n```ts\r\nconst svcProps: WebServiceProps = {\r\n  // ... other props\r\n  buildProps: {\r\n    buildSystem: 'Nixpacks',\r\n    installcmd: 'pnpm install', // optional\r\n    buildcmd: 'pnpm run build', // optional\r\n    startcmd: 'pnpm start',     // optional\r\n    environment: [\r\n      { NODE_ENV: 'production' }\r\n    ],\r\n    secrets: [\r\n      { key: 'DB_URL', resource: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:/my-app/DB_URL-abc123' }\r\n    ]\r\n  },\r\n};\r\n```\r\n\r\nWhen enabled, the pipeline will:\r\n\r\n- Install Nixpacks in the CodeBuild environment\r\n- Generate a Dockerfile using Nixpacks\r\n- Build and push the image to ECR\r\n- Deploy the image to ECS Fargate\r\n\r\nYou can customize install, build, and start commands using the respective properties. If not set, Nixpacks will auto-detect the best commands for your project.\r\n\r\nFor more advanced usage, see the [Nixpacks documentation](https://nixpacks.com/docs/usage/configuration).\r\n\r\n\r\n## Installation\r\n\r\nNavigate to your project directory and install the package and its required dependencies:\r\n\r\n```bash\r\nnpm i tsx @thunderso/cdk-webservice --save-dev\r\n```\r\n\r\n## Setup\r\n\r\n1. Login into the AWS console and note the `Account ID`. You will need it in the configuration step.\r\n\r\n2. Run the following commands to create the required CDK stack entrypoint at `stack/index.ts`. \r\n\r\n```bash\r\nmkdir stack\r\ncd stack\r\ntouch index.ts \r\n```\r\n\r\nYou should adapt the file to your project's needs.\r\n\r\n\u003e [!NOTE]\r\n\u003e Use different filenames such as `production.ts` and `dev.ts` for environments.\r\n\r\n\r\n## Configuration\r\n\r\n```ts\r\n// stack/index.ts\r\nimport { Cdk, WebServiceStack, type WebServiceProps } from \"@thunderso/cdk-webservice\";\r\n\r\nconst svcProps: WebServiceProps = {\r\n  env: {\r\n    account: 'your-account-id',\r\n    region: 'us-west-2'\r\n  },\r\n  application: 'your-application-id',\r\n  service: 'your-service-id',\r\n  environment: 'production',\r\n\r\n  rootDir: '', // supports monorepos. e.g. app/\r\n\r\n  // ... other props\r\n};\r\n\r\nnew WebServiceStack(\r\n  new Cdk.App(), \r\n  `${svcProps.application}-${svcProps.service}-${svcProps.environment}-stack`, \r\n  svcProps\r\n);\r\n```\r\n\r\n\r\n# Deploy\r\n\r\nRun `npm run build` before you deploy.\r\n\r\nBy running the following script, the CDK stack will be deployed to AWS.\r\n\r\n```bash\r\nnpx cdk deploy --all --app=\"npx tsx stack/index.ts\" \r\n```\r\n\r\nAfter deployment, the stack outputs the public DNS name of the Application Load Balancer:\r\n\r\n```\r\nOutputs:\r\n  LoadBalancerDNS: \u003cyour-load-balancer-url\u003e\r\n```\r\n\r\n\r\n## Deploy using GitHub Actions\r\n\r\nIn your GitHub repository, add a new workflow file under `.github/workflows/deploy.yml` with the following content:\r\n\r\n```yaml\r\nname: Deploy WebService to AWS\r\n\r\non:\r\n  push:\r\n\r\njobs:\r\n  deploy:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n      - uses: actions/checkout@v3\r\n      - uses: actions/setup-node@v3\r\n        with:\r\n          node-version: '20'\r\n      - run: npm ci\r\n      - run: npm run build # if you have a build step\r\n      - run: npx cdk deploy --require-approval never --all --app=\"npx tsx stack/index.ts\"\r\n        env:\r\n          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\r\n          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\r\n```\r\n\r\nAdd `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` as repository secrets in GitHub.\r\n\r\n\r\n## Destroy the Stack\r\n\r\nIf you want to destroy the stack and all its resources (including storage, e.g., access logs), run the following script:\r\n\r\n```bash\r\nnpx cdk destroy --all --app=\"npx tsx stack/index.ts\" \r\n```\r\n\r\n\r\n# Manage Domain with Route53\r\n\r\n1. [Create a hosted zone in Route53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html) for the desired domain, if you don't have one yet.\r\n\r\n  This is required to create DNS records for the domain to make the app publicly available on that domain. On the hosted zone details you should see the `Hosted zone ID` of the hosted zone.\r\n\r\n2. [Request a public regional certificate in the AWS Certificate Manager (ACM)](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html) for the desired domain in the same region as the service and validate it, if you don't have one yet.\r\n\r\n  This is required to provide the app via HTTPS on the public internet. Take note of the displayed `ARN` for the certificate. \r\n\r\n\u003e [!IMPORTANT]\r\n\u003e The certificate must be issued in the same region as the service.\r\n\r\n```ts\r\n// stack/index.ts\r\nconst svcProps: WebServiceProps = {\r\n  // ... other props\r\n\r\n  domain: 'api.example.com',\r\n  hostedZoneId: 'XXXXXXXXXXXXXXX',\r\n  regionalCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abcd1234-abcd-1234-abcd-1234abcd1234',\r\n};\r\n```\r\n\r\n\r\n# Configure the Service\r\n\r\nEach configuration property provides a means to fine-tune the performance and operational characteristics.\r\n\r\n```ts\r\n// stack/index.ts\r\nimport { CpuArchitecture } from 'aws-cdk-lib/aws-ecs';\r\n\r\nconst svcProps: WebServiceProps = {\r\n  // ... other props\r\n\r\n  serviceProps: {\r\n    // ... other props\r\n    dockerFile: 'Dockerfile',\r\n    architecture: CpuArchitecture.ARM64,\r\n    desiredCount: 1,\r\n    cpu: 256,\r\n    memorySize: 512,\r\n    port: 3000,\r\n  },\r\n};\r\n```\r\n\r\n### `dockerFile`\r\nPath to your Dockerfile relative to your project directory.  \r\n- **Type**: `text`\r\n- **Examples**: `Dockerfile.bun`, `dir/Dockerfile`,\r\n- **Default**: Looks for a `Dockerfile` in the root directory.\r\n\r\n### `architecture`\r\nDefines the instruction set architecture for the task.\r\n- **Type**: `CpuArchitecture`\r\n- **Examples**: `CpuArchitecture.ARM64`, `CpuArchitecture.X86_64`\r\n- **Default**: The architecture defaults to `CpuArchitecture.ARM64`.\r\n\r\n### `desiredCount`\r\nSpecifies the number of container instances of your service to run.\r\n- **Type**: `number`\r\n- **Examples**: `1`, `2`, `3`\r\n- **Default**: `1`\r\n\r\n### `cpu`\r\nThe amount of CPU units to allocate to the container (per task).\r\n- **Type**: `number`\r\n- **Examples**: `256`, `512`, `1024`\r\n- **Default**: `256`\r\n\r\n### `memorySize`\r\nThe amount of memory (in MiB) to allocate to the container (per task).\r\n- **Type**: `number`\r\n- **Examples**: `512`, `1024`, `2048`\r\n- **Default**: `512`\r\n\r\n### `port`\r\nThe port number on which your container listens for incoming traffic.\r\n- **Type**: `number`\r\n- **Examples**: `4321`, `3000`, `8080`\r\n- **Default**: `3000`\r\n\r\n\r\n## Environment variables\r\n\r\nPass environment variables to your service by:\r\n\r\n1. `variables`: Array of key-value pairs for plain environment variables.\r\n\r\n2. `secrets`: Array of objects with `key` and `resource` (Secrets Manager ARN). The library automatically adds permissions for Lambda to read these secrets.\r\n\r\nTo create a plaintext secret in AWS Secrets Manager using the AWS CLI:\r\n\r\n```bash\r\naws secretsmanager create-secret --name \"your-secret-name\" --secret-string \"your-secret-value\"\r\n```\r\n\r\n```ts\r\n// stack/index.ts\r\nconst svcProps: WebServiceProps = {\r\n  serviceProps: {\r\n    // ... other props\r\n\r\n    variables: [\r\n      { PUBLIC_FRONTEND_URL: 'https://example.com' },\r\n      { PUBLIC_ANALYTICS_ID: 'UA-XXXXXX' }\r\n    ],\r\n\r\n    secrets: [\r\n      { \r\n        key: 'DB_URL', \r\n        resource: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:/my-app/DB_URL-abc123' \r\n      },\r\n      { \r\n        key: 'DB_KEY', \r\n        resource: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:/my-app/DB_KEY-def456' \r\n      },\r\n    ],\r\n  },\r\n};\r\n```\r\n\r\n# Docker example\r\n\r\nHere is an example `Dockerfile` which can serve any Node application:\r\n\r\n```Dockerfile\r\n# ---- Build Stage ----\r\nFROM public.ecr.aws/docker/library/node:22-alpine AS builder\r\n\r\nWORKDIR /app\r\n\r\n# Copy all files\r\nCOPY . .\r\n\r\n# Install pnpm\r\nRUN corepack enable \u0026\u0026 corepack prepare pnpm@latest --activate\r\n\r\n# Install dependencies\r\nRUN pnpm install\r\n\r\n# Build Next.js app\r\nRUN pnpm run build\r\n\r\n# ---- Production Stage ----\r\nFROM public.ecr.aws/docker/library/node:22-alpine AS runner\r\n\r\nWORKDIR /app\r\n\r\nENV NODE_ENV=production\r\n\r\n# Install pnpm in production image\r\nRUN corepack enable \u0026\u0026 corepack prepare pnpm@latest --activate\r\n\r\n# Copy only necessary files from builder\r\nCOPY --from=builder /app/ ./\r\n\r\nEXPOSE 3000\r\n\r\nCMD [\"pnpm\", \"start\"]\r\n```\r\n\r\nYou might want to add a `.dockerignore` to minimize the context size:\r\n\r\n```\r\n.DS_Store\r\n.git\r\n.gitignore\r\nnode_modules\r\nstack\r\ncdk.out\r\n```\r\n\r\n# Cost\r\n\r\nBelow are estimated AWS costs for a typical deployment of this stack. \r\n\r\nExample: Next.js container in `us-east-1` with default configuration.\r\n\r\n## Baseline Cost (No Users, Always-On Service)\r\n\r\n| Component         | Monthly Cost (No Free Tier) |\r\n|-------------------|----------------------------|\r\n| Fargate (1 task)  | ~$9                        |\r\n| ALB               | ~$22                       |\r\n| ECR               | $0 (first 500MB free)      |\r\n| VPC/Subnets       | $0                         |\r\n| CloudWatch Logs   | \u003c$1                        |\r\n| Route53           | $0.50                      |\r\n| ACM (SSL)         | $0                         |\r\n| Data Transfer     | $0 (first 100GB free)      |\r\n| **Total**         | **~$33/month**             |\r\n\r\n- **With Free Tier:** $0 (if eligible, for 12 months, and under limits)\r\n- **Without Free Tier:** ~$33/month\r\n\r\n## 1000 Daily Active Users (DAU) Estimate\r\n\r\nAssumptions:\r\n- Each user visits once/day, 5 pageviews, 500KB/page (2.5MB/user/day)\r\n- Total data: 2.5GB/day, ~75GB/month\r\n- ALB: 1 LCU covers up to 25 new connections/sec, 3,000 active connections, 5Gbps, or 1M requests/hour (well within 1 LCU for 1000 DAU)\r\n- 2 Fargate tasks for redundancy\r\n\r\n| Component         | Monthly Cost (No Free Tier) |\r\n|-------------------|----------------------------|\r\n| Fargate (2 tasks) | ~$18                       |\r\n| ALB               | ~$22                       |\r\n| ECR               | $0                         |\r\n| VPC/Subnets       | $0                         |\r\n| CloudWatch Logs   | \u003c$1                        |\r\n| Route53           | $0.50                      |\r\n| ACM (SSL)         | $0                         |\r\n| Data Transfer     | ~$6.75 (75GB @ $0.09/GB)   |\r\n| **Total**         | **~$47/month**             |\r\n\r\n- **With Free Tier:** ~$41/month (if still eligible, and under 100GB data out)\r\n- **Without Free Tier:** ~$47/month\r\n\r\n### Notes\r\n- These are estimates; actual costs may vary based on usage, region, and AWS pricing changes.\r\n- If you add more tasks, NAT gateways, or use more storage/logs, costs will increase.\r\n- For production, consider scaling, backups, and monitoring costs.\r\n\r\n## Support\r\n\r\nFor help or feature requests, open an issue on [GitHub](https://github.com/thunder-so/cdk-webservice/issues).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthunder-so%2Fcdk-webservice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthunder-so%2Fcdk-webservice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthunder-so%2Fcdk-webservice/lists"}