Looking for Kubernetes? This guide covers ECS (Elastic Container Service) deployment. For Kubernetes/EKS deployment, see the EKS + Terraform guide.
Overview
Deploy Runlayer on AWS ECS (Elastic Container Service) with Fargate using Terraform. The stack runs entirely in your AWS account: VPC, ALB, Aurora, Redis, Secrets Manager, and ECS services. How Runlayer is delivered:
Runlayer grants your AWS account read access to the S3 module catalog and pull access to the ECR repositories during onboarding. Contact support@runlayer.com if
terraform init or image pulls return AccessDenied.
This deployment creates AWS resources that incur costs. Typical costs range
from $100-400/month depending on configuration.
Prerequisites
1
Install Tools
2
AWS Requirements
- AWS account with permission to create VPC, ECS, RDS, ElastiCache, ALB, IAM, Secrets Manager, S3, CloudWatch, and Lambda resources
- Domain name you control (for DNS records and SSL)
- Adequate service quotas (VPC, RDS, ECS; GPU quota if enabling ToolGuard)
- Outbound internet from private subnets (NAT or VPC endpoints) so ECS can pull images from ECR
- AWS provider
~> 6.0 - Anthropic first-time-use form submitted for the AWS account (see below) — this module sets
BEDROCK_ENABLED = true, and Runlayer Assistant always routes through Bedrock
Anthropic model access. Anthropic requires a use case details form before its models can be invoked in an AWS account, plus an accepted model agreement. You need this when the deployment invokes Anthropic models on Bedrock — typically
BEDROCK_ENABLED=true (Runlayer Assistant platform inference and optional Bedrock agent models). With BEDROCK_ENABLED=false, Runlayer Assistant binds an org AI provider instead; skip this step unless you also enable Bedrock inference elsewhere (for example BEDROCK_ANTHROPIC_MODELS_ENABLED for custom agents).The backend does both for you at startup and on login, in the account the Bedrock calls come from, using the model-access IAM permissions your deployment grants. Four settings describe the deployment on the form — BEDROCK_MODEL_ACCESS_COMPANY_NAME (defaults to Runlayer, the operator of the software making the calls), BEDROCK_MODEL_ACCESS_COMPANY_WEBSITE, BEDROCK_MODEL_ACCESS_INDUSTRY and BEDROCK_MODEL_ACCESS_INTENDED_USERS. Override them if you run this install yourself. They are never derived from your data: the form is submit-once, so a guessed answer would be permanent.Set BEDROCK_AUTO_MODEL_ACCESS=false to turn this off and do it by hand instead: Bedrock console → Model catalog → any Anthropic model → Submit use case details. Do the same if your deployment role predates the model-access permissions — the backend logs exactly which actions it is missing. AWS accepts the form once per account, or once at your AWS Organization’s management account, which member accounts inherit.Deploying outside the US? Also set RUNLAYER_ASSISTANT_BEDROCK_MODEL to your geography’s inference profile, for example au.anthropic.claude-opus-4-6-v1 in ap-southeast-2.Access takes up to 15 minutes to propagate. Until it does — or if this is skipped entirely — Bedrock-backed agents fail with Model use case details have not been submitted for this account; see troubleshooting for the CLI checks and Region caveats.3
Values from Runlayer
Runlayer provides during onboarding:
auth_client_id— WorkOS/Auth client IDauth_api_key— treat as a secret; pass viaTF_VAR_auth_api_key, never commit- Module version to pin (for example
v19.12.1) - Confirmation that your account is allowlisted for S3 module downloads and ECR image pulls
Quick Start
1. Create a working directory with a root module that references the published archive:aws and aws.route53 into the module, even when DNS lives in the same account.
Delivery details
Terraform module (S3)
Module archives are published to:source form:
source, then:
Container images (ECR)
By default the module pulls Runlayer images from CustomerDistribution ECR:app_version. Override it, or supply your own image map:
- URIs must be public ECR (
public.ecr.aws/...) or private ECR (account.dkr.ecr.region.amazonaws.com/...) - Every URI must include an explicit tag or
@sha256:digest — no implicitlatest app_versionandecr_repositoriesare mutually exclusive
Configuration options
Required inputs
Smart production-ready defaults include:
- Database: Aurora PostgreSQL Serverless v2, private subnets, automated backups
- Cache: ElastiCache Redis in private subnets
- Security: Public ALB by default; private DB/cache; Secrets Manager for app secrets
- SSL: Automatic wildcard certificate lookup; set
enable_acm_dns_validation = trueto create + validate a cert via Route53 - Scaling: Backend default 4096 CPU / 8192 MB; frontend 256 CPU / 512 MB; auto-scaling enabled
- Network: Multi-AZ VPC with public/private subnets (IPv6 on by default; set
enable_ipv6 = falsefor IPv4-only) - Monitoring: CloudWatch logs for all services
Optional configuration
Database Configuration
Database Configuration
Bring Your Own Database / Cache
Bring Your Own Database / Cache
Skip Aurora and/or ElastiCache when you operate PostgreSQL and Redis/Valkey yourself. Postgres and Redis can be configured independently.ECS tasks receive
POSTGRES_* env vars and Secrets Manager entries for PLATFORM_DB_PASSWORD and REDIS_URL. Ensure private subnets can reach your endpoints. For Kubernetes, see the Runlayer Operator database and Redis contract.Security Configuration
Security Configuration
Dual ALB Setup (Split-Horizon DNS)
Dual ALB Setup (Split-Horizon DNS)
- Public DNS → public ALB
- Private DNS → internal ALB
- ECS services register with both ALBs
- WAF applies only to the public ALB
VPC Peering for Cross-VPC Connectivity
VPC Peering for Cross-VPC Connectivity
existing_vpc_id).Service Scaling
Service Scaling
Defaults already set production-ready CPU/memory. To override, replace the full Reserve
services_configurations map (partial maps are not merged):backend.priority + 1 for the /mcp alias listener rule (module validation enforces this).Network Configuration
Network Configuration
Monitoring & Alerting
Monitoring & Alerting
Optional feature flags
Optional feature flags
Runlayer Deploy is always enabled by the ECS module.
Agent Sandbox (Optional)
Agent Sandbox (Optional)
sandboxMode: k8s, gVisor or Kata on the nodes) is operator/GKE — see Runlayer Operator — K8s Agent Sandbox.Runlayer Assistant always runs on Bedrock in this account — it ignores Settings → AI Providers by design, so it works without configuring a provider. Model access is handled as described above; this module exposes it as bedrock_auto_model_access, bedrock_model_access_company_name, bedrock_model_access_company_website, bedrock_model_access_industry and bedrock_model_access_intended_users.Secrets management
All application secrets live in AWS Secrets Manager in your account. The module creates two primary secrets (plus an optional LLM gateway secret):
Design notes:
SECRET_KEYandMASTER_SALTare isolated in the restricted secret so only privileged task roles can read them.- The app secret and restricted secret share the same random name suffix to avoid recreate collisions during Secrets Manager recovery windows.
- Prefer
TF_VAR_*/ a secrets backend for sensitive inputs — do not commit API keys to git. - After deploy, rotate non-key values with Secrets Manager (then force a new ECS deployment so tasks pick up the new version). Rotate
SECRET_KEY/MASTER_SALTviasecret_key/master_saltinstead — Terraform reverts out-of-band edits to the restricted secret on the next apply.
Module outputs (attributes)
After apply, useful outputs include:Deployment
Automated database setup
Database initialization is automated during apply: What happens automatically:- Migration task waits for PostgreSQL, then runs
alembic upgrade head - Backend services only roll out after migrations succeed (Terraform waits up to 30 minutes by default)
- Setup activity is logged to CloudWatch under
anysource-backend-migration-logs-<environment> - Re-running
terraform applyafter interruption is safe (idempotent + advisory lock)
Verify
Architecture
Cost estimation
Costs vary by region and usage. Use AWS Pricing
Calculator for precise estimates.
Common use cases
Private enterprise deployment
High availability production
Development environment
Troubleshooting
terraform init cannot download the module
terraform init cannot download the module
Confirm your AWS credentials can
s3:GetObject on runlayer-infrastructure-modules and that Runlayer allowlisted your account or IAM principal. Contact support@runlayer.com if access was not provisioned during onboarding.ECS tasks cannot pull images
ECS tasks cannot pull images
- Confirm ECR pull access to
088332244652(CustomerDistribution) - Private subnets need NAT or ECR VPC endpoints
- Check ECS service events for
CannotPullContainerError/AccessDeniedException
SSL Certificate Issues
SSL Certificate Issues
Wildcard lookup fails (default behavior):DNS validation fails (when For cross-account DNS, confirm the
enable_acm_dns_validation = true):aws.route53 provider assume_role can write validation records.Application Not Accessible
Application Not Accessible
Migration task failures
Migration task failures
Check CloudWatch
anysource-backend-migration-logs-<environment>. Re-running terraform apply is safe — the migration uses an advisory lock and rolls back on failure.High Costs
High Costs
- Use
environment = "development"for testing - Reduce database
min_capacity/max_capacity - Lower service
desired_countand CPU/memory - Set shorter
backup_retention - Consider
single_nat_gateway = truefor non-prod
ECS vs EKS: which to choose?
Next Steps
EKS + Terraform
Deploy on Kubernetes using EKS with Terraform for more advanced scenarios
Runlayer Operator
Deploy the application after provisioning Kubernetes infrastructure