Skip to main content
AWS ECS with Fargate runs MergeWatch as a serverless container task — no EC2 instances to manage. Choose this option when you want MergeWatch on AWS but need VPC networking, private subnets, or predictable billing instead of the Lambda-based deployment.

Overview

This guide covers creating an ECS service running the MergeWatch container on Fargate, connecting it to an RDS PostgreSQL instance, and exposing the webhook endpoint through an Application Load Balancer (ALB) or API Gateway.

Prerequisites

1

Install the AWS CLI

aws --version   # requires 2.0.0+
aws sts get-caller-identity   # confirm credentials
2

Set up networking

You need a VPC with at least two subnets (public for the ALB, private for the Fargate tasks). If you do not have one, use the default VPC or create one with:
aws ec2 create-default-vpc
3

Gather your GitHub App credentials

VariableDescription
GITHUB_APP_IDNumeric App ID from the GitHub App settings page
GITHUB_PRIVATE_KEYPEM-formatted private key generated for the App
GITHUB_WEBHOOK_SECRETSecret used to validate incoming webhook payloads
4

Choose an LLM provider

Set LLM_PROVIDER to your preferred provider. If using bedrock, no static API key is needed — attach Bedrock permissions to the ECS task role instead.

Deploy to ECS / Fargate

1

Create an ECS cluster

aws ecs create-cluster --cluster-name mergewatch
2

Store secrets in AWS Secrets Manager

aws secretsmanager create-secret \
  --name mergewatch/github-private-key \
  --secret-string "YOUR_PRIVATE_KEY"

aws secretsmanager create-secret \
  --name mergewatch/github-webhook-secret \
  --secret-string "YOUR_WEBHOOK_SECRET"

aws secretsmanager create-secret \
  --name mergewatch/anthropic-api-key \
  --secret-string "YOUR_ANTHROPIC_KEY"
3

Create the task definition

Create a file called task-definition.json:
{
  "family": "mergewatch",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::YOUR_ACCOUNT:role/mergewatchTaskRole",
  "containerDefinitions": [
    {
      "name": "mergewatch",
      "image": "ghcr.io/santthosh/mergewatch:latest",
      "portMappings": [
        { "containerPort": 3000, "protocol": "tcp" }
      ],
      "environment": [
        { "name": "GITHUB_APP_ID", "value": "YOUR_APP_ID" },
        { "name": "LLM_PROVIDER", "value": "anthropic" },
        { "name": "DATABASE_URL", "value": "postgresql://USER:PASSWORD@rds-host:5432/mergewatch" }
      ],
      "secrets": [
        { "name": "GITHUB_PRIVATE_KEY", "valueFrom": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:mergewatch/github-private-key" },
        { "name": "GITHUB_WEBHOOK_SECRET", "valueFrom": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:mergewatch/github-webhook-secret" },
        { "name": "ANTHROPIC_API_KEY", "valueFrom": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:mergewatch/anthropic-api-key" }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/mergewatch",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ]
}
Register the task definition:
aws ecs register-task-definition --cli-input-json file://task-definition.json
4

Create the ECS service

aws ecs create-service \
  --cluster mergewatch \
  --service-name mergewatch \
  --task-definition mergewatch \
  --desired-count 1 \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"
5

Set up an Application Load Balancer

Create an ALB in your public subnets and add a target group pointing to the ECS service on port 3000. The ALB provides a stable HTTPS endpoint for GitHub webhooks.
# Create the ALB
aws elbv2 create-load-balancer \
  --name mergewatch-alb \
  --subnets subnet-aaa subnet-bbb \
  --security-groups sg-xxx

# Create a target group
aws elbv2 create-target-group \
  --name mergewatch-tg \
  --protocol HTTP \
  --port 3000 \
  --vpc-id vpc-xxx \
  --target-type ip \
  --health-check-path /webhook

# Create an HTTPS listener (requires an ACM certificate)
aws elbv2 create-listener \
  --load-balancer-arn ALB_ARN \
  --protocol HTTPS \
  --port 443 \
  --certificates CertificateArn=ACM_CERT_ARN \
  --default-actions Type=forward,TargetGroupArn=TG_ARN
If using LLM_PROVIDER=bedrock, you do not need an ANTHROPIC_API_KEY. Instead, attach an IAM policy with bedrock:InvokeModel permission to the ECS task role (mergewatchTaskRole). The SDK uses the task role credentials automatically — no static keys required.

Set up Postgres

Amazon RDS (recommended)

Managed PostgreSQL with automated backups, Multi-AZ failover, and Performance Insights.

Aurora Serverless v2

Auto-scaling PostgreSQL-compatible database. Scales down to 0.5 ACU during idle periods.
1

Create an RDS instance

aws rds create-db-instance \
  --db-instance-identifier mergewatch-db \
  --db-instance-class db.t4g.micro \
  --engine postgres \
  --engine-version 15 \
  --master-username mergewatch \
  --master-user-password YOUR_DB_PASSWORD \
  --allocated-storage 20 \
  --vpc-security-group-ids sg-xxx
2

Create the database

psql -h mergewatch-db.xxx.us-east-1.rds.amazonaws.com \
  -U mergewatch -c "CREATE DATABASE mergewatch;"
Update the DATABASE_URL in your task definition to point to the RDS endpoint.
Place the RDS instance in the same VPC and security group as the Fargate tasks. Do not expose the database to the public internet.

Configure the webhook URL

Set the webhook URL on your GitHub App to the ALB DNS name (or your custom domain) followed by /webhook:
https://mergewatch-alb-123456.us-east-1.elb.amazonaws.com/webhook
If you use API Gateway instead of an ALB, the URL will look like:
https://abc123.execute-api.us-east-1.amazonaws.com/webhook

Next steps