Amazon ECS

Deploy Stategraph on AWS ECS Fargate with a complete, production-ready infrastructure stack using Terraform. This guide uses the official Stategraph ECS Terraform module for a simple, maintainable deployment.

Prerequisites

Before deploying Stategraph on ECS, ensure you have:

  • Terraform 1.0+ installed
  • AWS CLI 2.0+ configured with credentials
  • AWS Account with appropriate permissions
  • Existing VPC with private and public subnets (or use the complete example to create one)
  • ACM certificate for HTTPS
  • Domain name for the application
  • Access to the Stategraph server image — it's distributed privately so we can make sure your team has the support it needs; reach out and we'll get you set up

Architecture Overview

Stategraph on ECS uses a managed, AWS-native architecture:

Internet
    │
    ▼
Application Load Balancer (HTTPS:443)
    │
    ▼
ECS Service (Fargate Tasks in Private Subnets)
    │
    ├─▶ RDS PostgreSQL (Multi-AZ)
    ├─▶ Secrets Manager (Credentials)
    └─▶ CloudWatch Logs (Monitoring)

What the module creates:

  • ECS cluster and service (Fargate launch type)
  • Application Load Balancer with HTTPS listener
  • RDS PostgreSQL database (Multi-AZ by default)
  • Security groups (ALB, ECS, RDS)
  • IAM roles for ECS tasks
  • Secrets Manager secrets for credentials
  • CloudWatch Log Group for container logs
  • Auto Scaling policies (optional)

What you must provide:

  • VPC and subnets
  • ACM certificate for HTTPS
  • Domain name

Quick Start

1. Request ACM Certificate

Before deploying, create an SSL certificate in AWS Certificate Manager:

# Request certificate for your domain
aws acm request-certificate \
  --domain-name stategraph.example.com \
  --validation-method DNS \
  --region us-east-1

# Note the CertificateArn from the output

Follow the AWS Console instructions to validate the certificate via DNS. This typically takes 5-10 minutes.

2. Create Terraform Configuration

Create a new directory and a main.tf file:

mkdir stategraph-ecs && cd stategraph-ecs
# main.tf
module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # Network configuration (use your existing VPC)
  vpc_id             = "vpc-xxxxx"
  private_subnet_ids = ["subnet-xxxxx", "subnet-yyyyy"]
  public_subnet_ids  = ["subnet-aaaaa", "subnet-bbbbb"]

  # Domain and certificate
  domain_name     = "stategraph.example.com"
  certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxx"

  # Environment
  environment = "production"

  # Tags (optional)
  tags = {
    Project   = "Stategraph"
    ManagedBy = "Terraform"
  }
}

output "alb_dns_name" {
  description = "Load balancer DNS - create a CNAME record pointing your domain here"
  value       = module.stategraph.alb_dns_name
}

output "database_endpoint" {
  description = "RDS database endpoint"
  value       = module.stategraph.database_endpoint
  sensitive   = true
}

3. Initialize Terraform

terraform init

4. Review the Plan

terraform plan

This will show all the resources that Terraform will create.

5. Deploy

terraform apply

Deployment takes approximately 10-15 minutes.

6. Configure DNS

After deployment, create a DNS record pointing your domain to the ALB:

# Get the ALB DNS name
terraform output alb_dns_name

# Create a CNAME record in your DNS provider:
# Name: stategraph.example.com
# Type: CNAME
# Value: <alb-dns-name>

Or use a Route53 alias record:

# Get the ALB zone ID for Route53 alias
terraform output -raw alb_zone_id

7. Access Stategraph

After DNS propagation (5-10 minutes), access Stategraph at:

https://stategraph.example.com

Cookie Security

Stategraph derives cookie security from the configured URL (STATEGRAPH_UI_BASE):

  • https:// URLs → cookies are set with the Secure flag (recommended for production)
  • http:// URLs → cookies are set without the Secure flag

The ECS module sets this to https://<domain_name> by default. Ensure the domain_name variable matches your certificate and DNS.

Configuration Options

Required Variables

Variable Description Example
vpc_id VPC ID where resources will be created vpc-xxxxx
private_subnet_ids Private subnet IDs for ECS and RDS ["subnet-xxxxx", "subnet-yyyyy"]
public_subnet_ids Public subnet IDs for ALB ["subnet-aaaaa", "subnet-bbbbb"]
domain_name Domain name for the application stategraph.example.com
certificate_arn ACM certificate ARN for HTTPS arn:aws:acm:...

Optional Variables (Common Settings)

Variable Description Default
environment Environment name production
ecs_task_cpu ECS task CPU units 1024
ecs_task_memory ECS task memory (MB) 2048
ecs_desired_count Number of ECS tasks 2
enable_autoscaling Enable ECS autoscaling true
database_instance_class RDS instance type db.t3.medium
database_multi_az Enable Multi-AZ for RDS true
stategraph_image Docker image <stategraph-server-image>:latest

For a complete list of variables, see the module documentation included with your private module access, or reach out and we'll walk you through it.

Using an Existing VPC

If you already have a VPC with public and private subnets, simply reference them in your configuration:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # Reference your existing VPC
  vpc_id             = "vpc-0123456789abcdef0"
  private_subnet_ids = ["subnet-aaa", "subnet-bbb"]  # ECS tasks and RDS
  public_subnet_ids  = ["subnet-ccc", "subnet-ddd"]  # ALB

  # ... other required variables
}

VPC Requirements:

  • At least 2 private subnets in different availability zones (for ECS and RDS)
  • At least 2 public subnets in different availability zones (for ALB)
  • NAT Gateway or NAT instances for private subnet internet access
  • DNS hostnames enabled

Creating a New VPC

If you need to create a VPC, use the terraform-aws-modules/vpc module. A complete working example is included with your private module access — reach out if you don't have it yet.

Example with VPC creation:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "stategraph-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  enable_dns_hostnames = true
}

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  vpc_id             = module.vpc.vpc_id
  private_subnet_ids = module.vpc.private_subnets
  public_subnet_ids  = module.vpc.public_subnets

  # ... other variables
}

Using External PostgreSQL

If you have an existing PostgreSQL database, set create_database = false and provide connection details:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # ... other required variables

  create_database           = false
  external_database_host    = "postgres.example.com"
  external_database_port    = 5432
  external_database_name    = "stategraph"
  external_database_username = var.database_username  # Use variables for sensitive data
  external_database_password = var.database_password
}

Requirements:

  • PostgreSQL 13+ (17.x recommended)
  • Network connectivity from ECS tasks (configure security groups)
  • SSL/TLS support recommended

Authentication

Enable OAuth authentication with Google or OIDC:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # ... other required variables

  oauth_enabled       = true
  oauth_provider      = "google"  # or "oidc"
  oauth_client_id     = var.oauth_client_id
  oauth_client_secret = var.oauth_client_secret

  # For OIDC provider:
  # oauth_issuer_url = "https://accounts.google.com"
}

OAuth Redirect URI — the path is /oauth2/{provider}/callback:

https://stategraph.example.com/oauth2/google/callback   # for Google
https://stategraph.example.com/oauth2/oidc/callback     # for OIDC

Configure this callback URL in your OAuth provider settings.

Important: Store OAuth credentials securely using Terraform variables (create a terraform.tfvars file and add it to .gitignore):

# terraform.tfvars (do not commit)
oauth_client_id     = "your-client-id"
oauth_client_secret = "your-client-secret"

For detailed OAuth configuration, see the Authentication guide.

Enable cost estimation

Cost analysis is off by default. The pricing service ships inside the server image; turn it on by
setting STATEGRAPH_COST_ENABLED=true on the server container. Set it in the task definition
so cost survives task replacements and rolling deployments. The bundled pricing service runs in the
same container, so STATEGRAPH_PRICING_SERVICE_URL already defaults to http://localhost:8090
set it only to point at an external pricing service.

Add it to the server container's environment block in the task definition:

"containerDefinitions": [
  {
    "name": "stategraph",
    "environment": [
      { "name": "STATEGRAPH_COST_ENABLED", "value": "true" }
    ]
  }
]

On first boot the pricing service loads the price book into the cloud_pricing database in the
background, so the server and UI stay available immediately. Use a managed or volume-backed
PostgreSQL so cloud_pricing has durable storage. See Cost Setup for
verification, refresh cadence, and air-gapped installs.

Health Checks

Stategraph provides two health check endpoints for ALB and ECS configuration:

Endpoint Purpose Available
/health/live Liveness probe — returns 200 as long as nginx is running Immediately on startup
/health/ready Readiness probe — returns 200 when the backend is ready After database migrations complete

The module configures these automatically. During container startup, database migrations run before the backend starts. The /health/live endpoint remains available throughout, while /health/ready will return 502 until migrations are complete.

For detailed configuration options, see the Health Checks reference.

Scaling

Auto-Scaling (Enabled by Default)

The module configures ECS autoscaling based on CPU and memory utilization:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # ... other variables

  enable_autoscaling          = true
  ecs_min_count               = 1
  ecs_desired_count           = 2
  ecs_max_count               = 4
  autoscaling_cpu_threshold   = 70  # Scale when CPU > 70%
  autoscaling_memory_threshold = 80  # Scale when memory > 80%
}

Manual Scaling

To scale manually (or for development), disable autoscaling:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # ... other variables

  enable_autoscaling = false
  ecs_desired_count  = 3  # Fixed count
}

Vertical Scaling

Increase task resources for more demanding workloads:

module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.0.0"  # module source provided when you get access: https://stategraph.com/contact

  # ... other variables

  ecs_task_cpu    = 2048  # 2 vCPU
  ecs_task_memory = 4096  # 4 GB
}

Upgrading

Update Stategraph Version

  1. Update the image tag in your configuration:
module "stategraph" {
  # ... other variables
  stategraph_image = "<stategraph-server-image>:1.2.0"  # image URL provided when you get access: https://stategraph.com/contact
}
  1. Apply the change:
terraform apply

ECS will perform a rolling deployment with zero downtime.

Update Module Version

  1. Update the module reference:
module "stategraph" {
  source = "<stategraph-ecs-module>?ref=v1.1.0"  # module source provided when you get access: https://stategraph.com/contact
  # ...
}
  1. Reinitialize and apply:
terraform init -upgrade
terraform plan
terraform apply

Monitoring

View Container Logs

# Get the log group name from Terraform
aws logs tail $(terraform output -raw cloudwatch_log_group_name) --follow

# Filter by error level
aws logs tail /ecs/stategraph-production --filter-pattern "ERROR"

View ECS Service Status

# Get cluster and service names from Terraform
aws ecs describe-services \
  --cluster $(terraform output -raw ecs_cluster_name) \
  --services $(terraform output -raw ecs_service_name)

CloudWatch Metrics

The module automatically enables Container Insights for enhanced monitoring. View metrics in the CloudWatch Console under Container Insights > ECS Clusters.

Key Metrics:

  • CPUUtilization: Percentage of allocated CPU used
  • MemoryUtilization: Percentage of allocated memory used
  • TargetResponseTime: ALB target response time
  • HealthyHostCount: Number of healthy tasks
  • RequestCount: Number of requests to ALB

Database Credentials

Access database credentials from Secrets Manager:

aws secretsmanager get-secret-value \
  --secret-id $(terraform output -raw database_secret_arn) \
  --query SecretString --output text | jq -r '.password'

Complete Example

For a complete, working example that includes VPC creation and all optional features, see the examples/complete directory included with your private module access. Reach out if you need access.

Module Documentation

Detailed module documentation — including all variables, outputs, advanced configuration options, and examples — is distributed privately along with the module. Reach out through our contact page and we'll get you set up with access.

Next Steps