Skip to main content
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 ID
  • auth_api_key — treat as a secret; pass via TF_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:
2. Deploy:
Provider wiring is required: always pass 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:
Terraform source form:
To upgrade, bump the version in source, then:

Container images (ECR)

By default the module pulls Runlayer images from CustomerDistribution ECR:
The module pins a default app_version. Override it, or supply your own image map:
Validation rules (enforced by the module):
  • 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 implicit latest
  • app_version and ecr_repositories are mutually exclusive
The module grants its ECS task execution role permission to pull from Runlayer’s CustomerDistribution registry. Private repositories in your deployment account are pullable through the standard execution role. Repositories in another AWS account need both task-role permission and a repository policy granting your account pull access.

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 = true to 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 = false for IPv4-only)
  • Monitoring: CloudWatch logs for all services

Optional configuration

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.
Use case: public access (for example ChatGPT / external integrations) plus private network access on the same hostname via split-horizon DNS.
  • Public DNS → public ALB
  • Private DNS → internal ALB
  • ECS services register with both ALBs
  • WAF applies only to the public ALB
Security note: every peering connection must set peer_owner_id. The module validates ownership before accepting the connection.
VPC peering only applies when the module creates the VPC (not with existing_vpc_id).
Defaults already set production-ready CPU/memory. To override, replace the full services_configurations map (partial maps are not merged):
Reserve backend.priority + 1 for the /mcp alias listener rule (module validation enforces this).
Use an existing VPC — all three variables must be provided together:
Private subnets need NAT (or VPC endpoints) for ECR pulls; public subnets need an internet gateway for the ALB. For topology options, see Networking.
Automatic CloudWatch alarms cover: ECS CPU/memory, RDS, Redis, ALB latency/unhealthy targets/5XX, and VPC flow logs.
Runlayer Deploy is always enabled by the ECS module.
By default, Agent Sandbox routes LLM calls through the backend Anthropic proxy. To use OpenAI or an OpenAI-compatible gateway, add a provider in Settings → AI Providers (no Terraform change needed).This Terraform path provisions the ECS / AgentCore sandbox. In-cluster kubernetes-sigs Agent Sandbox (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_KEY and MASTER_SALT are 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_SALT via secret_key/master_salt instead — 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 apply after 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

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.
  • Confirm ECR pull access to 088332244652 (CustomerDistribution)
  • Private subnets need NAT or ECR VPC endpoints
  • Check ECS service events for CannotPullContainerError / AccessDeniedException
Wildcard lookup fails (default behavior):
DNS validation fails (when enable_acm_dns_validation = true):
For cross-account DNS, confirm the aws.route53 provider assume_role can write validation records.
Check CloudWatch anysource-backend-migration-logs-<environment>. Re-running terraform apply is safe — the migration uses an advisory lock and rolls back on failure.
  • Use environment = "development" for testing
  • Reduce database min_capacity / max_capacity
  • Lower service desired_count and CPU/memory
  • Set shorter backup_retention
  • Consider single_nat_gateway = true for 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