Skip to content

ECS on EC2 — Terraform Example

Progress checklist

This example provisions:

  • An S3 bucket (versioning + SSE-S3 enabled)
  • An S3 Files file system and mount targets in each provided subnet
  • IAM roles (file system role, ECS task role, and a separate ECS instance role/profile)
  • Security groups (compute → mount target on NFS port 2049; DNS and HTTPS egress for the agent and task)
  • A new ECS cluster
  • One ECS-optimized Amazon Linux 2023 container instance (recommended AMI via SSM)
  • A native aws_ecs_task_definition with s3files_volume_configuration
  • An ECS service with launch_type = EC2 running one demo task

This is the EC2-launch counterpart to ECS Fargate.

  1. Confirm prerequisites.

    RequirementMinimum version
    Terraform1.5
    AWS provider6.41 (s3files_volume_configuration on task definitions)
    AWS CLI2.34.26 (for log tail / optional verification)

    You need a VPC with private subnets that can reach AWS APIs (NAT gateway or VPC endpoints).

  2. Clone the example.

    Terminal window
    git clone https://github.com/jajera/terraform-aws-s3-files.git
    cd terraform-aws-s3-files/examples/ecs-ec2
    • Directoryexamples/ecs-ec2/ - main.tf - terraform.tfvars.example - terraform.tfvars (you create this)
      • …
  3. Create terraform.tfvars.

    Terminal window
    cp terraform.tfvars.example terraform.tfvars

    Edit terraform.tfvars:

    vpc_id = "vpc-0123456789abcdef0"
    subnet_ids = ["subnet-aaaaaaaaaaaaaaaaa", "subnet-bbbbbbbbbbbbbbbbb"]
    # Optional overrides (defaults shown):
    # aws_region = "ap-southeast-6"
    # instance_subnet_id = null # defaults to first subnet_ids entry
    # instance_type = "t3.small"
    # container_image = "public.ecr.aws/amazonlinux/amazonlinux:2023"
    # log_retention_days = 7
    # bucket_name = null # auto-generated: s3files-demo-<random>
    # bucket_force_destroy = true
    VariableDefaultRequiredDescription
    vpc_id—yesVPC for mount targets, instance, and task ENIs
    subnet_ids—yesSubnets for mount targets and task ENIs
    instance_subnet_idfirst subnet_ids entrynoSubnet for the container instance
    aws_regionap-southeast-6noAWS region
    instance_typet3.smallnoEC2 instance type for the container instance
    container_imagepublic.ecr.aws/amazonlinux/amazonlinux:2023noDemo task image
    log_retention_days7noCloudWatch log retention
    bucket_nameauto-generatednoLeave null for s3files-demo-<random>
    bucket_force_destroytruenoAllow destroy even when the bucket contains objects
  4. Initialise and apply.

    Terminal window
    terraform init
    terraform plan
    terraform apply

    When apply finishes:

    Terminal window
    terraform output
    OutputDescription
    ecs_cluster_nameCluster created by this example
    ecs_instance_idContainer instance ID
    ecs_service_nameECS service name
    task_definition_familyTask definition family
    log_groupCloudWatch log group
    file_system_idS3 Files file system ID
    bucket_nameBacking S3 bucket name
  5. Confirm the service is healthy.

    Terminal window
    aws ecs describe-services \
    --cluster "$(terraform output -raw ecs_cluster_name)" \
    --services "$(terraform output -raw ecs_service_name)" \
    --region ap-southeast-6 \
    --query 'services[0].{status:status,running:runningCount,desired:desiredCount}'

    Expected output:

    {
    "status": "ACTIVE",
    "running": 1,
    "desired": 1
    }

    Wait until runningCount equals desiredCount (1). First boot can take a few minutes while the instance registers with ECS and the mount targets become available. If the service fails on first apply because no container instance is registered yet, wait for the instance to join the cluster and run terraform apply again.

    Optional: confirm the instance advertises ecs.capability.storage.s3-files via aws ecs describe-container-instances on the cluster from ecs_cluster_name.

  6. Verify via CloudWatch Logs.

    Terminal window
    aws logs tail \
    "$(terraform output -raw log_group)" \
    --follow \
    --region ap-southeast-6

    Expected output includes:

    ====S3Files-df====
    Filesystem Size Used Avail Use% Mounted on
    127.0.0.1:/ 8.0E 0 8.0E 0% /mnt/s3files
    ====listing====
    total 12
    drwxr-xr-x. 3 root root 10240 ... .
    drwxr-xr-x. 1 root root 21 ... ..
    drwx------. 2 root root 10240 ... .s3files-lost+found-fs-...
    -rw-r--r--. 1 root root 41 ... ecs-s3files-demo.txt
    ====read-back====
    written-at-2026-09-19T19:00:07Z-ec2-demo
    ====done====

    Press Ctrl+C to stop tailing.

  7. Tear down.

    Terminal window
    terraform destroy