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

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 = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # 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

⚠️ Important - Secure Cookie Configuration

Stategraph uses secure cookies for authentication. For proper operation:

  • Production: Must use HTTPS via ACM certificate on ALB
  • The domain_name variable must match your certificate and DNS
  • Self-signed certificates will cause authentication failures

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 ghcr.io/stategraph/stategraph-server:latest

For a complete list of variables, see the module documentation.

Using an Existing VPC

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

module "stategraph" {
  source = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # 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. See the complete example for a full working configuration.

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 = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  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 = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # ... 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, GitHub, or OIDC:

module "stategraph" {
  source = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # ... other required variables

  oauth_enabled       = true
  oauth_provider      = "google"  # or "github" 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:

https://stategraph.example.com/api/v1/auth/callback

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.

Create an API Key

Terraform authenticates to Stategraph using an API key. Without one, terraform init will fail with a 401 Unauthorized error.

  1. Log in to the UI at https://stategraph.example.com
  2. Go to Settings > API Keys
  3. Click Create API Key and copy the token
  4. Set the environment variables Terraform expects:
export TF_HTTP_USERNAME="session"
export TF_HTTP_PASSWORD="<your-api-key>"

You're now ready to configure Terraform to store state in Stategraph.

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 = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # ... 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 = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # ... other variables

  enable_autoscaling = false
  ecs_desired_count  = 3  # Fixed count
}

Vertical Scaling

Increase task resources for more demanding workloads:

module "stategraph" {
  source = "github.com/stategraph/terraform-aws-stategraph-ecs?ref=v1.0.0"

  # ... 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 = "ghcr.io/stategraph/stategraph-server:1.2.0"
}
  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 = "github.com/stategraph/stategraph//terraform/aws-ecs?ref=v1.1.0"
  # ...
}
  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 in the repository.

Module Documentation

For detailed module documentation including all variables, outputs, and advanced configuration options, see:

Next Steps