Deploy in production
This guide covers two production paths: running the global npm package against your own PostgreSQL and Redis, and provisioning the bundled AWS stack with the repository’s installer. For a single-machine trial, use Get started instead; for a container deployment, see Deploy with Docker. Bootstrap credentials, single sign-on, and safe upgrades are covered in Operate a self-hosted Chorus.
Run the global package against external PostgreSQL
Section titled “Run the global package against external PostgreSQL”Install the Chorus command globally on the host that will run the web application:
npm install --global @chorus-aidlc/chorusPoint Chorus at an existing PostgreSQL database with DATABASE_URL and supply the
required authentication and secret variables, then start it:
DATABASE_URL='postgresql://chorus:password@db.internal:5432/chorus' \NEXTAUTH_SECRET="${NEXTAUTH_SECRET:?Set a persistent random secret first}" \SUPER_ADMIN_EMAIL='admin@example.com' \SUPER_ADMIN_PASSWORD_HASH='$2b$10$...' \chorusOn startup Chorus applies any pending database migrations automatically
(prisma migrate deploy, exposed as the db:migrate script) and then serves the web
application on port 8637. The database must already exist and be reachable; Chorus
does not create the server for you on this path.
The variables Chorus reads in a production run:
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string, postgresql://user:password@host:port/dbname. |
NEXTAUTH_SECRET | For multiple instances | Signing secret shared by all replicas. For a single npm instance, it may be omitted: chorus persists one in ~/.chorus-data/.secret by default. Known placeholders in the environment are ignored with a warning; a persisted placeholder or empty key stops startup. |
SUPER_ADMIN_EMAIL | Yes | Email that bootstraps the /admin SuperAdmin panel. |
SUPER_ADMIN_PASSWORD_HASH | Yes | Bcrypt hash of the SuperAdmin password. |
DEFAULT_USER | Optional | Enables a built-in email/password login for first access. |
DEFAULT_PASSWORD | Optional | Password for the built-in login. |
REDIS_URL | Optional | Redis connection string. Required once you run more than one instance (see below). |
See Operate a self-hosted Chorus for how these bootstrap credentials work, how to generate the bcrypt hash, and how to turn the built-in login off.
Run more than one instance
Section titled “Run more than one instance”Chorus propagates live updates (the SSE event stream) across instances through Redis. Set
REDIS_URL to a shared Redis so every instance publishes and receives the same events:
REDIS_URL='redis://default:password@redis.internal:6379'Redis is required for cross-instance event propagation. Without REDIS_URL, Chorus
falls back to an in-memory event bus that is scoped to a single process — updates made on
one instance never reach the others. A single-instance deployment can run without Redis on
that in-memory fallback, but any deployment with more than one instance must configure a
shared Redis.
All instances must also share the same secure NEXTAUTH_SECRET, so Chorus-signed sessions remain valid whichever instance receives a request.
Deploy the AWS CDK stack
Section titled “Deploy the AWS CDK stack”Chorus bundles an AWS CDK stack under packages/chorus-cdk and a repository-root
install.sh that drives it interactively. The stack stands up a complete, HTTPS-fronted
deployment with managed PostgreSQL and Redis.
Prerequisites
Section titled “Prerequisites”install.sh checks for aws, node, pnpm, and valid AWS credentials. Configure
aws configure or AWS_PROFILE first. Certificate requirements depend on the mode below.
Choose the deployment mode
Section titled “Choose the deployment mode”alb(default): public ALB with HTTPS on port 443; requires an ACM certificate in the deployment region. A custom domain is optional.cloudfront: public HTTPS through CloudFront, forwarding to a private ALB on HTTP port 80 through a VPC origin. No certificate is needed for the default*.cloudfront.netdomain. For a custom domain, supply both the domain and an ACM certificate inus-east-1. Caching is disabled for authenticated pages and API responses.
Choose the mode in ./install.sh, or pass -c deployMode=cloudfront to CDK.
default_deploy.sh preserves the choice. Non-interactive installs use
CHORUS_INSTALL_NONINTERACTIVE=1, DEPLOY_MODE=alb|cloudfront, and the other required
installer variables. Neither mode creates DNS records: point a custom domain at the
AlbDnsName or CloudFrontDomainName stack output, and update the OIDC callback URL.
Run the installer
Section titled “Run the installer”From the repository root:
./install.shThe installer prompts for the deployment configuration:
| Prompt | Required | Notes |
|---|---|---|
| Deployment mode | No | alb (default) or cloudfront. |
| Stack name | No | Defaults to Chorus. |
| ACM Certificate ARN | Mode-dependent | Required in the deployment region for alb; required in us-east-1 only with a custom domain for cloudfront. |
| Custom domain | No | For cloudfront, pair with a us-east-1 certificate; otherwise use the distribution domain. |
| Super admin email | Yes | Bootstraps the /admin SuperAdmin account. |
| Super admin password | Yes | Minimum 8 characters. Hashed with bcrypt at synth time; the plaintext is never stored in the template. |
| NextAuth secret | No | Generated at each synth if left blank. Supply one persistent value to keep sessions valid across redeployments. |
The stack shares NEXTAUTH_SECRET through Secrets Manager, but does not read the existing
value back during synth. Reuse the same value in the installer or CDK’s nextAuthSecret
context on every deployment. If you previously left it blank, preserve the existing
Secrets Manager value before redeploying to avoid rotating it.
After collecting the answers, install.sh installs and builds the CDK package, bootstraps
the CDK environment, and deploys the stack. It also writes a re-runnable
default_deploy.sh with your answers so later deploys do not re-prompt.
What the stack provisions
Section titled “What the stack provisions”The stack (packages/chorus-cdk/lib/{chorus-stack,service,database,cache}.ts) creates:
| Component | What it is | Key configuration |
|---|---|---|
| Application Load Balancer | Public HTTPS:443 in alb; private HTTP:80 origin in cloudfront. | Routes to ECS; 60-minute idle timeout. |
| CloudFront | Public HTTPS endpoint, only in cloudfront mode. | Private VPC origin; caching disabled; optional custom domain. |
| ECS Fargate service | Runs the Chorus container in private subnets. | Desired count 2, 1024 CPU units / 2048 MiB, deployment circuit breaker with automatic rollback. |
| Aurora Serverless v2 (PostgreSQL) | Managed PostgreSQL cluster. | Encrypted storage; credentials auto-generated into Secrets Manager; 1-day backup retention. |
| ElastiCache Serverless (Redis) | Managed Redis for cross-instance events. | RBAC user; password stored in Secrets Manager. |
| Secrets Manager | Holds the generated database and Redis credentials plus the app secrets. | Injected into the ECS task at runtime. |
Deploy, update, and destroy
Section titled “Deploy, update, and destroy”| Action | Command |
|---|---|
| First deploy | ./install.sh |
| Re-deploy or update | ./default_deploy.sh (or pnpm cdk:deploy) |
| Destroy | pnpm cdk:destroy |
packages/chorus-cdk is the authoritative source for the stack. Read it there when you
need exact resource definitions or want to adjust capacity, retention, or networking.