Skip to content

AWS Installation

Deploy Broch on AWS with ECS Fargate, an Application Load Balancer, and RDS PostgreSQL. The Terraform module lives in broch-io/broch-deploy/terraform/aws-ecs — clone the repo, fill in terraform.tfvars, and terraform apply.

Marketplace listing: an AWS Marketplace listing with a one-click CloudFormation stack is on the roadmap. Until then, the Terraform module is the supported deployment path.

  • VPC with 2 public + 2 private subnets across 2 AZs, single NAT gateway
  • Application Load Balancer with ACM cert (apex + wildcard, DNS-validated via Route 53)
  • ECS Fargate cluster + task definition + service (1 task by default)
  • RDS PostgreSQL 17 in private subnets, encrypted at rest (db.t4g.micro by default)
  • Secrets Manager entries: master key (generated BROCH_MASTER_KEY), DB password, connection string
  • IAM execution role scoped tight to just this stack’s secrets
  • Route 53 A-ALIAS records: apex + wildcard pointing at the ALB
  • CloudWatch Logs group, 30-day retention

All resources are created in your account. Broch has no access to your environment.

This stack runs ALB + Fargate + RDS + a NAT gateway. To estimate spend, use the AWS Pricing Calculator with your chosen sizes; the module README notes the resource tradeoffs.

  • Terraform 1.6+
  • AWS credentials with permissions to create VPC, ECS, RDS, ALB, IAM, ACM, and Secrets Manager resources
  • A Route 53 hosted zone for your wildcard hostname’s parent domain
  • Wildcard domain & DNS configured
  • Identity provider app registration created
  • License — activated in-app after first sign-in (nothing to set before deploy)
Terminal window
git clone https://github.com/broch-io/broch-deploy.git
cd broch-deploy/terraform/aws-ecs
cp terraform.tfvars.example terraform.tfvars
$EDITOR terraform.tfvars
terraform init
terraform plan
terraform apply # 5-10 min on first run; RDS is the long pole

After apply:

Terminal window
echo "Broch is at: $(terraform output -raw broch_url)"
curl -fsS "$(terraform output -raw broch_url)/healthz"

DNS records are created automatically by the Terraform — no manual record entry needed. The ACM cert is DNS-validated against your Route 53 zone, also automatic.

Update the image tag and re-apply:

Terminal window
$EDITOR terraform.tfvars # set broch_image = "ghcr.io/broch-io/broch:1.6.0"
terraform apply

ECS rolls out a new task version. Existing traffic drains gracefully via the ALB. Database migrations run automatically on the new task’s first start.

For force-refreshing the image at the same tag (e.g. pulling a re-tagged :latest):

Terminal window
aws ecs update-service \
--cluster broch-cluster \
--service broch-service \
--force-new-deployment \
--region us-east-1

RDS handles automated backups with the configured retention period (7 days default — see backup_retention_period in the module’s database.tf). Snapshot manually before risky operations:

Terminal window
aws rds create-db-snapshot \
--db-instance-identifier broch-postgres \
--db-snapshot-identifier broch-pre-upgrade-$(date +%Y%m%d)

Secrets Manager entries can be rotated via the AWS console / CLI. Force a new ECS deployment to pick up the new values:

Terminal window
aws secretsmanager update-secret \
--secret-id broch/postgres-password \
--secret-string "$(openssl rand -base64 32)"
aws ecs update-service \
--cluster broch-cluster \
--service broch-service \
--force-new-deployment

Tradeoffs / what the default module is not

Section titled “Tradeoffs / what the default module is not”

The default terraform.tfvars.example values prioritise a minimal footprint over availability. Before production:

  • Set multi_az = true on the RDS resource for cross-AZ failover
  • Increase desired_count to 2+ if you need zero-downtime deploys
  • Set skip_final_snapshot = false and deletion_protection = true on RDS
  • Add WAF in front of the ALB if you’re exposed to abuse

See the module README for the full list.

If you’d rather run Broch on a single EC2 instance with Docker Compose (simpler, single-VM), use the Docker Compose installation guide and run it on an Ubuntu EC2 instance you provision yourself.

Terminal window
terraform destroy

Note: skip_final_snapshot = true in the default config means Postgres data is deleted permanently on destroy. Snapshot first if you want to keep it.