Skip to content

AWS Deployment Guide

Use the AWS Terraform foundation when SkillMeat needs managed infrastructure or an AWS-hosted development environment.

For compute, storage, network, and external-service requirements by deployment method, see Deployment System Requirements.

Plan / Decision Matrix

Mode Use When Infrastructure Shape
dev-ec2 You want the fastest disposable AWS dev box with the same Compose profiles used locally. One public EC2 instance running Docker Compose. Dependencies are co-located, and enterprise starts Postgres through Compose.
dev-fargate You want cloud parity with ECS/Fargate behavior at low cost. Public ECS web/API tasks, no NAT, one task each, tiny RDS, low log retention, deletion protection off.
staging You need a managed pre-production environment. Fargate web/API services, managed RDS PostgreSQL, Secrets Manager, CloudWatch Logs.
production You need the managed production path. Fargate web/API services, private RDS PostgreSQL, production retention/protection settings, Secrets Manager, CloudWatch Logs.

The production and staging managed AWS path is Fargate plus RDS managed services. dev-fargate keeps that architecture but makes it disposable and low-cost. dev-ec2 is intentionally different: it is a single-box Compose deployment for development and profile testing, with public EC2 web/API URLs and optional SSH key or SSM access.

Layout

Terraform is expected under deploy/aws/terraform/:

deploy/aws/terraform/
├─ envs/
│  ├─ staging/
│  ├─ production/
│  ├─ dev-fargate/
│  └─ dev-ec2/
└─ modules/
   ├─ skillmeat_aws/
   └─ skillmeat_ec2_dev/

The root Makefile wraps common Terraform commands so operators can use the same command shape for all environments.

Architecture

The managed Fargate environments provision this AWS shape for SkillMeat:

  • Application Load Balancer routes public traffic to the web and API services.
  • ECS Fargate runs separate web and api tasks from GHCR-published images.
  • RDS PostgreSQL runs in private networking and is not publicly reachable.
  • AWS Secrets Manager stores database credentials and application secrets for ECS task injection.
  • CloudWatch Logs collects web and API task logs.
Users -> ALB -> ECS Fargate web
             -> ECS Fargate API -> RDS PostgreSQL private subnet
                                -> Secrets Manager
                                -> CloudWatch Logs

dev-fargate uses the same skillmeat_aws module with development inputs: public ECS tasks, no NAT, one API task, one web task, tiny RDS, low retention, and deletion protection disabled.

dev-ec2 runs the existing Docker Compose deployment on one EC2 instance. It supports the local, local-auth, and enterprise Compose profiles. All dependencies run on the instance; in enterprise, Postgres starts through Compose instead of RDS. Use the public EC2 web/API URLs for access, and configure an SSH key or SSM if operator shell access is needed.

Image Configuration

Terraform consumes published GHCR image tags for the web and API containers. Publish images before planning or applying an environment update, then point the environment variables or Terraform inputs at the intended tags. Prefer immutable version tags over latest so task definition changes are explicit and reviewable.

Next.js inlines NEXT_PUBLIC_* values during pnpm build. Runtime ECS environment variables do not change client-side values already compiled into the web image. Build the web image with the correct public API URL, auth mode, and Clerk publishable key for the target environment before publishing the tag Terraform will deploy.

Local Commands

Set TF_ENV to dev-fargate, dev-ec2, staging, or production:

make terraform-fmt
make terraform-validate TF_ENV=dev-fargate
make terraform-plan TF_ENV=dev-ec2
make terraform-validate TF_ENV=staging
make terraform-plan TF_ENV=production

Shortcut targets:

make terraform-validate-staging
make terraform-validate-production
make terraform-validate-dev-fargate
make terraform-validate-dev-ec2
make terraform-plan-staging
make terraform-plan-production
make terraform-plan-dev-fargate
make terraform-plan-dev-ec2

terraform-fmt checks all Terraform files under deploy/aws/terraform. terraform-validate runs terraform init -backend=false before validation. terraform-plan uses the selected environment root and requires AWS credentials plus any configured remote backend access.

Usage Examples

Validate the disposable Fargate development environment:

make terraform-validate-dev-fargate

Plan a single-box EC2 Compose environment:

make terraform-plan-dev-ec2

For dev-ec2, set compose_profile = "local" for SQLite/no-auth, compose_profile = "local-auth" for SQLite with Clerk, or compose_profile = "enterprise" for Compose-managed PostgreSQL on the same instance. local-auth and enterprise require the relevant Clerk values in env_vars; enterprise should also set POSTGRES_PASSWORD in secret_env_vars so the Postgres container and API DATABASE_URL agree.

Use the generic target for any environment root:

make terraform-validate TF_ENV=dev-ec2
make terraform-plan TF_ENV=staging

CI Validation

.github/workflows/terraform.yml runs when files under deploy/aws/** change. It checks Terraform formatting, then validates the dev-fargate, dev-ec2, staging, and production environment roots with terraform init -backend=false. The workflow does not read secrets and does not run terraform plan or terraform apply.

Release Checklist

  1. Build and publish web/API images to GHCR with environment-appropriate values.
  2. Update the selected Terraform environment inputs to reference the new image tags.
  3. Run make terraform-validate TF_ENV=<env>.
  4. Run make terraform-plan TF_ENV=<env> with AWS credentials.
  5. Review the plan before applying through the approved operator workflow.