> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shipfastai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy Shipfastai to AWS with Terraform

> Provision a production AWS environment for Shipfastai using included Terraform modules for ECS Fargate, RDS PostgreSQL, and an Application Load Balancer.

Shipfastai's Enterprise tier includes a complete set of Terraform modules that provision a production-ready AWS environment. The infrastructure runs your backend and frontend as containerized services on ECS Fargate, backed by a managed RDS PostgreSQL database, and fronted by an Application Load Balancer with TLS termination. This page explains what is provisioned, how to deploy it, and how to run database migrations once your services are running.

<Warning>
  The Terraform infrastructure described on this page is included exclusively in the **Enterprise tier**. If you are on the Basic or Pro tier, refer to the [Railway & Vercel](/deployment/railway-vercel) guide instead.
</Warning>

<Note>
  Estimated AWS costs for a small production workload (2 Fargate tasks each for backend and frontend, a `db.t3.medium` RDS instance, one NAT Gateway, and an ALB) are roughly **\$50–100 per month**. Costs scale with traffic, task count, and data transfer. Use the [AWS Pricing Calculator](https://calculator.aws) to estimate your specific configuration before deploying.
</Note>

## Prerequisites

Before running Terraform, make sure you have the following installed and configured on your machine:

* **AWS CLI** configured with credentials that have sufficient IAM permissions to create VPCs, ECS clusters, RDS instances, ECR repositories, and IAM roles. Run `aws sts get-caller-identity` to verify your credentials.
* **Terraform 1.5 or later**. Run `terraform version` to check.
* **Docker**, for building and pushing your backend and frontend images to ECR.

## What the Terraform modules provision

The modules in `products/enterprise/infra/terraform/` create the following AWS resources:

| Resource                      | Description                                                                                                                                            |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **VPC**                       | Isolated network with public and private subnets across two Availability Zones, a NAT Gateway, and an Internet Gateway                                 |
| **ECS cluster**               | Fargate cluster with Container Insights enabled; runs the backend API service and the frontend web service                                             |
| **ECR repositories**          | Two private image registries — one for the backend, one for the frontend — with image scanning on push                                                 |
| **RDS PostgreSQL**            | PostgreSQL 15 instance (`db.t3.medium` by default) in private subnets, with Multi-AZ enabled in production, automated backups, and deletion protection |
| **Application Load Balancer** | Internet-facing ALB in public subnets; routes `/api` traffic to the backend target group and all other traffic to the frontend target group            |
| **Auto Scaling**              | CPU-based auto scaling for both the API service (2–10 tasks) and the web service (2–6 tasks)                                                           |
| **CloudWatch**                | Log groups for both ECS services, plus alarms for high CPU and error rates                                                                             |
| **Secrets Manager**           | A single secret that holds sensitive runtime variables injected into ECS task definitions                                                              |

## Initialize and deploy

<Steps>
  <Step title="Navigate to the Terraform directory">
    ```bash theme={null}
    cd products/enterprise/infra/terraform
    ```
  </Step>

  <Step title="Create your tfvars file">
    Copy the example variables file and fill in your values:

    ```bash theme={null}
    cp terraform.tfvars.example terraform.tfvars
    ```

    Open `terraform.tfvars` and set at minimum:

    ```hcl theme={null}
    aws_region   = "us-east-1"
    environment  = "production"
    app_name     = "shipfastai-enterprise"
    db_password  = "a-strong-random-password"
    domain_name  = "api.yourdomain.com"
    ```

    You can also override instance sizes, task counts, and auto-scaling limits. Refer to `variables.tf` for the full list of inputs and their defaults.
  </Step>

  <Step title="Initialize Terraform">
    ```bash theme={null}
    terraform init
    ```

    This downloads the AWS provider and configures the S3 backend for remote state. Before running this command, create an S3 bucket for Terraform state and update the `backend "s3"` block in `main.tf` with your bucket name and key.
  </Step>

  <Step title="Preview the plan">
    ```bash theme={null}
    terraform plan
    ```

    Review the output carefully. Terraform will list every resource it intends to create. Verify that the region, instance sizes, and CIDR blocks match your expectations before proceeding.
  </Step>

  <Step title="Apply the configuration">
    ```bash theme={null}
    terraform apply
    ```

    Type `yes` when prompted. The apply takes approximately 10–15 minutes, with the RDS instance taking the longest to become available. When it completes, Terraform prints the ALB DNS name, ECR repository URLs, and RDS endpoint as outputs.
  </Step>
</Steps>

## Pushing Docker images

After `terraform apply` succeeds, build your images locally and push them to the ECR repositories Terraform created. The repository URLs are available in the Terraform outputs.

```bash theme={null}
# Authenticate Docker with ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  <your-account-id>.dkr.ecr.us-east-1.amazonaws.com

# Build and push the backend image
docker build -t shipfastai-backend ./products/enterprise/backend
docker tag shipfastai-backend:latest \
  <backend-ecr-url>:latest
docker push <backend-ecr-url>:latest

# Build and push the frontend image
docker build -t shipfastai-frontend ./products/enterprise/frontend
docker tag shipfastai-frontend:latest \
  <frontend-ecr-url>:latest
docker push <frontend-ecr-url>:latest
```

Replace `<backend-ecr-url>` and `<frontend-ecr-url>` with the values from the `backend_ecr_url` and `frontend_ecr_url` Terraform outputs. After pushing, force a new deployment so ECS pulls the updated images:

```bash theme={null}
aws ecs update-service \
  --cluster shipfastai-enterprise-cluster \
  --service shipfastai-enterprise-api \
  --force-new-deployment

aws ecs update-service \
  --cluster shipfastai-enterprise-cluster \
  --service shipfastai-enterprise-web \
  --force-new-deployment
```

## Running migrations on AWS

You need to run Alembic migrations whenever you deploy a new schema version. There are two common approaches.

**Run migrations as a one-off ECS task.** Use the AWS CLI to start a task that overrides the container command with the Alembic upgrade command:

```bash theme={null}
aws ecs run-task \
  --cluster shipfastai-enterprise-cluster \
  --task-definition shipfastai-enterprise-api \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[<private-subnet-id>],securityGroups=[<ecs-tasks-sg-id>],assignPublicIp=DISABLED}" \
  --overrides '{"containerOverrides":[{"name":"api","command":["alembic","upgrade","head"]}]}'
```

Retrieve the private subnet IDs and security group ID from the Terraform outputs (`private_subnet_ids` and the ECS tasks security group).

**Use a bastion host for interactive access.** If you prefer to connect directly to the database, launch a small EC2 instance in a public subnet within the same VPC, configure its security group to allow inbound SSH, and add a rule to the RDS security group allowing connections from the bastion instance on port 5432. You can then SSH in and run Alembic from there.

For automated deployments, the ECS task approach is recommended because it requires no additional infrastructure and uses the same Docker image as your running service.
