AWS deployment — step by step
deploy/aws = Terraform module: ECS Fargate (Web + MCP) behind ALB, RDS Postgres, CloudWatch logs.
1. Prerequisites
- Terraform ≥ 1.5 + AWS credentials (
aws configure/ env vars) with rights to make VPC-scoped resources, ECS, RDS, ALB, IAM. - Three images in registry ECS can pull (ECR, or GHCR public).
2. Initialize
cd deploy/aws
terraform init
3. Apply
terraform apply \
-var image_registry=ghcr.io/your-org/cmind \
-var image_tag=1.0.0 \
-var owner_email=you@example.com \
-var owner_password='Change-Me-Str0ng!' \
-var pg_password="$(openssl rand -hex 16)" \
-var discovery_join_token="$(openssl rand -hex 24)"
Makes: RDS Postgres (appdb), ECS cluster, Fargate services for Web + MCP, ALB (Web at /,
MCP at /mcp), security groups, CloudWatch log group, ADOT (AWS Distro for
OpenTelemetry) collector sidecar in each task. App exports OTLP to sidecar, which ships
traces to X-Ray, metrics to CloudWatch (EMF, namespace cmind); logs stay on
awslogs driver as compact JSON. Discovery on for Web. Task role grants sidecar
X-Ray + CloudWatch write access — no collector to run yourself.
Uses account's default VPC/subnets for brevity. For production, wire own VPC, private subnets, HTTPS listener (ACM cert).
4. Get the URLs
terraform output web_url # ALB root
terraform output mcp_url # ALB /mcp
Open web_url, sign in with owner (forced password change on first login).
5. Add node agents (separate)
Fargate disallows privileged/DinD, so run agents elsewhere pointing at web_url:
- ECS on EC2 — capacity provider with
privileged = truetask definitions runningcmind-node-agent. - EKS — Helm chart (kubernetes.md) with
nodeAgent.privileged=true.
Set NodeAgent__MainUrl=<web_url>, NodeAgent__AdvertiseUrl=<agent reachable url>,
NodeAgent__JwtSecret=<discovery_join_token>. Agents self-register — see
../operations/node-discovery.md.
6. Verify
aws logs tail /ecs/cmind --since 5m # compact JSON logs
curl -s "$(terraform output -raw web_url)/version"
Production notes
- Add HTTPS listener + ACM certificate; restrict ALB security group.
- Store secrets in AWS Secrets Manager / SSM, inject via task-definition
secretsinstead of plaintextenvironment. - Enable RDS Multi-AZ + backups.
- Traces (X-Ray), metrics (CloudWatch EMF), logs (CloudWatch Logs) wired automatically via
ADOT sidecar; correlate on
trace_id. See ../operations/logging.md. - App already points
OTEL_EXPORTER_OTLP_ENDPOINTat in-task sidecar; repoint to external collector if you prefer to centralize.
Copy-trading agent + Secrets Manager (S5)
deploy/aws/copy-agent.tf adds copy-agent ECS Fargate service hosting CopyEngineSupervisor
(App:Copy:Enabled=true, App:Features:CopyTrading=true) with no ALB — worker holding long-lived
cTrader sockets. DB connection string stored in AWS Secrets Manager, injected through
task's secrets block (execution role granted secretsmanager:GetSecretValue on just that secret),
not plaintext env. Each task's NodeName defaults to its container hostname (unique per Fargate task), so
DB lease attributes running profiles per task — two tasks never double-host one. Scale
copy_agent_count to add copy capacity; DataProtection key ring shared through Postgres, so any task
can decrypt stored Open API tokens.