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_namevariable 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.
- Log in to the UI at
https://stategraph.example.com - Go to Settings > API Keys
- Click Create API Key and copy the token
- 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
- Update the image tag in your configuration:
module "stategraph" {
# ... other variables
stategraph_image = "ghcr.io/stategraph/stategraph-server:1.2.0"
}
- Apply the change:
terraform apply
ECS will perform a rolling deployment with zero downtime.
Update Module Version
- Update the module reference:
module "stategraph" {
source = "github.com/stategraph/stategraph//terraform/aws-ecs?ref=v1.1.0"
# ...
}
- 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
- Configure your first Terraform state — connect Terraform using your API key
- Set up authentication
- Perform gap analysis on AWS resources