Skip to content

AWS ECS

Deploy Terrateam on AWS using the terraform-aws-terrateam Terraform module. This creates an ECS/Fargate service behind an Application Load Balancer with an RDS PostgreSQL database — all managed as infrastructure as code.

  • Completed the Setup Wizard (see above) to generate GitHub App credentials
  • AWS account with permissions for ECS, RDS, ALB, IAM, Secrets Manager, and CloudWatch
  • Terraform >= 1.3 installed
  • VPC with subnets:
    • Public subnets for the ALB (at least two, in different availability zones)
    • Private subnets with NAT gateway for ECS tasks and RDS, or public subnets with assign_public_ip = true
  • (Optional) An ACM certificate for HTTPS

The module creates:

  • ECS Cluster + Fargate Service running the Terrateam container
  • Application Load Balancer with health checks on /health
  • RDS PostgreSQL instance with encrypted storage
  • Secrets Manager secrets for GitHub App credentials and the database password
  • CloudWatch Log Group for container logs
  • Security Groups restricting traffic between ALB, ECS, and RDS
  • IAM Roles for task execution (pulling images, reading secrets) and the task itself
  1. Create your Terraform configuration

    Create a new directory and main.tf:

    provider "aws" {
    region = "us-east-1" # Choose your region
    }
    module "terrateam" {
    source = "github.com/terrateamio/terraform-aws-terrateam"
    vpc_id = "vpc-0123456789abcdef0"
    public_subnet_ids = ["subnet-aaa", "subnet-bbb"]
    private_subnet_ids = ["subnet-ccc", "subnet-ddd"]
    domain = "terrateam.example.com"
    # Optional: enable HTTPS
    # acm_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx"
    tags = {
    Environment = "production"
    }
    }
    output "alb_dns_name" {
    value = module.terrateam.alb_dns_name
    }
    output "ecs_cluster_name" {
    value = module.terrateam.ecs_cluster_name
    }
    output "ecs_service_name" {
    value = module.terrateam.ecs_service_name
    }
    output "secret_arns" {
    value = module.terrateam.secret_arns
    }
    output "terrateam_url" {
    value = module.terrateam.terrateam_url
    }
  2. Deploy the infrastructure

    Terminal window
    terraform init
    terraform apply

    This creates all resources including the ECS cluster, ALB, RDS instance, and empty Secrets Manager secrets. The RDS instance takes several minutes to provision.

  3. Set up DNS and HTTPS

    You need a domain name that points to the ALB. This is the URL you will use for GitHub webhooks, OAuth callbacks, and the Terrateam UI.

    Create a DNS record pointing your domain to the ALB:

    terrateam.example.com CNAME <alb_dns_name>

    If using Route 53, create an alias record using the alb_dns_name and alb_zone_id outputs.

    For HTTPS (recommended for production), request an ACM certificate for your domain, then set acm_certificate_arn in your module configuration and run terraform apply again. The module will create an HTTPS listener and redirect HTTP to HTTPS.

  4. Populate GitHub App secrets

    The module creates empty Secrets Manager secrets. Populate them with the credentials from the Setup Wizard:

    Terminal window
    # Get the secret ARNs from Terraform output
    terraform output secret_arns
    # Populate each secret
    aws secretsmanager put-secret-value \
    --secret-id <github_app_id ARN> \
    --secret-string '<YOUR_APP_ID>'
    aws secretsmanager put-secret-value \
    --secret-id <github_app_client_id ARN> \
    --secret-string '<YOUR_CLIENT_ID>'
    aws secretsmanager put-secret-value \
    --secret-id <github_app_client_secret ARN> \
    --secret-string '<YOUR_CLIENT_SECRET>'
    aws secretsmanager put-secret-value \
    --secret-id <github_webhook_secret ARN> \
    --secret-string '<YOUR_WEBHOOK_SECRET>'

    For the PEM private key, if you have a .pem file:

    Terminal window
    aws secretsmanager put-secret-value \
    --secret-id <github_app_pem ARN> \
    --secret-string file://private-key.pem

    If you are using the .env file from the Setup Wizard, the PEM value contains literal \n escape sequences. Extract and convert it to real newlines:

    Terminal window
    PEM_RAW=$(grep '^GITHUB_APP_PEM=' .env | sed 's/^GITHUB_APP_PEM=//')
    printf '%b' "$PEM_RAW" | aws secretsmanager put-secret-value \
    --secret-id <github_app_pem ARN> \
    --secret-string file:///dev/stdin
  5. Redeploy ECS to pick up secrets

    Force a new deployment so the ECS tasks load the populated secrets:

    Terminal window
    aws ecs update-service \
    --cluster $(terraform output -raw ecs_cluster_name) \
    --service $(terraform output -raw ecs_service_name) \
    --force-new-deployment

    Wait for the new task to pass health checks (1-2 minutes). You can monitor progress in the CloudWatch Logs console under the /ecs/<name> log group, or check readiness with:

    Terminal window
    curl $(terraform output -raw terrateam_url)/health
  6. Configure GitHub App

    Navigate to your GitHub App settings and configure the following:

    Webhook URL:

    1. In the General tab, find the Webhook section
    2. Set the webhook URL to:
      <your-terrateam-url>/api/github/v1/events
      Replace <your-terrateam-url> with the terrateam_url Terraform output (e.g. https://terrateam.example.com).
    3. Save your changes

    Enable UI access (OAuth):

    1. Check the box “Request user authorization (OAuth) during installation”
    2. Set the Callback URL to:
      <your-terrateam-url>/api/github/v1/callback
    3. Save your changes
  7. Verify the deployment

    Check the health endpoint using the terrateam_url output:

    Terminal window
    curl $(terraform output -raw terrateam_url)/health

    A 200 response means both the application and database are healthy.

    Access the Terrateam UI at your terrateam_url and log in with your GitHub account.

  8. Install the GitHub App

    Install your GitHub App on the organization or repositories you want Terrateam to manage:

    1. Navigate to your GitHub App’s public page (e.g. https://github.com/apps/<your-app-name>)
    2. Click Install
    3. Select the organization and repositories to enable
    4. Create a pull request with a Terraform change to verify Terrateam responds

If the ECS task is failing or the health check is not passing, check the container logs:

Terminal window
aws logs tail /ecs/<name> --region <region> --follow

Common issues:

  • Task fails immediately: Check that all Secrets Manager secrets have been populated (step 4). Empty secrets cause the task to crash on startup.
  • 502 or 503 from ALB: The ECS task is still starting or running database migrations. Wait 2-5 minutes on first deploy.
  • OAuth login redirects to wrong URL: Run terraform apply and then force a new ECS deployment (step 5) to pick up the updated domain configuration.
NameDescriptionTypeDefault
vpc_idVPC IDstring
public_subnet_idsPublic subnet IDs for ALBlist(string)
private_subnet_idsPrivate subnet IDs for ECS + RDSlist(string)
domainPublic FQDN for the instancestring
nameName prefix for all resourcesstring"terrateam"
acm_certificate_arnACM certificate ARN for HTTPSstringnull
container_imageDocker imagestring"ghcr.io/terrateamio/terrat-oss:latest"
container_cpuFargate CPU unitsnumber512
container_memoryFargate memory (MiB)number1024
desired_countECS task countnumber1
db_instance_classRDS instance classstring"db.t4g.micro"
db_engine_versionPostgreSQL versionstring"14.18"
db_multi_azEnable RDS Multi-AZboolfalse
db_deletion_protectionEnable RDS deletion protectionbooltrue
db_backup_retention_periodRDS backup retention daysnumber7
alb_ingress_cidr_blocksCIDRs allowed to reach the ALBlist(string)["0.0.0.0/0"]
assign_public_ipAssign public IP to ECS tasksboolfalse
extra_environmentAdditional container env varslist(object)[]
db_skip_final_snapshotSkip final snapshot on RDS destroyboolfalse
tagsTags for all resourcesmap(string){}
NameDescription
alb_dns_nameALB DNS name
alb_zone_idALB Route 53 zone ID (for alias records)
ecs_cluster_nameECS cluster name
ecs_service_nameECS service name
task_role_arnECS task role ARN (attach additional policies here)
db_endpointRDS endpoint
secret_arnsMap of all Secrets Manager ARNs
terrateam_urlConstructed URL for the instance
alb_security_group_idALB security group ID
ecs_security_group_idECS security group ID
rds_security_group_idRDS security group ID

To update the Terrateam container image or change configuration:

Terminal window
terraform apply

To force a redeployment of the ECS service (e.g., after updating secret values):

Terminal window
aws ecs update-service \
--cluster <ecs_cluster_name> \
--service <ecs_service_name> \
--force-new-deployment