Tahmid Choudhury
ProjectsBlogResume
Back to all projects

Loading...

Built by hand.

Production-Grade Deployment on ECS

May 20, 2026•

2 min read

DemoArchitectureTechnology StackCloud & InfrastructureInfrastructure as CodeCI/CD & AutomationBackend & ApplicationNetworking & SecurityRepository StructureHow to set up locally1. Clone the repository2. Create an environment file3. Start the application4. Open the app5. Stop the application6. Remove volumes and reset the databaseCI/CD1. Docker Build & Push1a. Docker Build1b. Push to ECR2. Terraform Plan2a. Terraform Plan Steps3. Terraform Apply3a. Terraform Apply Steps3b. Post Deploy Check4. Terraform Destroy4a. Terraform Destroy StepsAuthor

This project deploys a Dockerised analytics application to AWS ECS Fargate using Terraform and GitHub Actions CI/CD. It includes networking, load balancing, HTTPS, PostgreSQL, observability, and modular infrastructure configuration.

I built this project to showcase my cloud, networking, and infrastructure skills. I chose Umami because I had already used it for hosted frontend projects.


Demo

URL: https://analytics.tahmidchoudhury.uk

![ECS demo video](./docs/ecs-demo.gif)


Architecture

The infrastructure is designed for high availability, security, and scalability.

Key components:

  • VPC with public and private subnets across multiple AZs
  • Application Load Balancer (ALB) with a health check on `/api/heartbeat`
  • ECS Fargate service running tasks in private subnets
  • CloudWatch enabled for DB and Task logs
  • NAT Gateway for outbound internet access from private subnets
  • ACM certificate for HTTPS
  • Route 53 for DNS
  • S3 for a remote Terraform statefile with state-lock enabled
  • GitHub Actions for CI/CD using OIDC

Technology Stack

Cloud & Infrastructure

  • AWS ECS Fargate
  • AWS ECR
  • AWS ALB (Application Load Balancer)
  • AWS Route53
  • AWS ACM
  • AWS RDS PostgreSQL
  • AWS VPC

Infrastructure as Code

  • Terraform
  • Modular Terraform Architecture

CI/CD & Automation

  • GitHub Actions
  • Docker
  • Docker Compose

Backend & Application

  • PostgreSQL
  • Umami Analytics
  • Node.js

Networking & Security

  • Security Groups
  • Public & Private Subnets
  • NAT Gateway
  • IAM Roles & Policies
  • HTTPS / TLS

Repository Structure

shell
app
├── docker-compose.yml
├── Dockerfile
└── src
    └── app
        └── api
            └── heartbeat
...
infra
├── bootstrap
│   ├── main.tf
│   ├── modules
│   │   └── ecr
│   │   └── s3
│   ├── provider.tf
│   └── variables.tf
├── envs
├── modules
│   ├── acm
│   ├── alb
│   ├── secrets
│   ├── cloudwatch
│   ├── dns
│   ├── ecs
│   ├── iam
│   ├── networking
│   ├── rds
│   └── security_groups
├── backend.tf
├── main.tf
├── outputs.tf
└── variables.tf
.github
└── workflows
    ├── docker-build-push.yml
    ├── terraform-apply.yml
    ├── terraform-destroy.yml
    └── terraform-plan.yml

How to set up locally

1. Clone the repository

shell

# By HTTPS
git clone https://github.com/tahmidachoudhury/ecs-umami-analytics.git
# OR by SSH
git clone git@github.com:tahmidachoudhury/ecs-umami-analytics.git

cd ecs-umami-analytics

2. Create an environment file

Create a .env file in the root of the project:

shell
touch .env

Add the required environment variables:

ts
DATABASE_URL=postgresql://umami:umami@db:5432/umami
APP_SECRET=your-random-secret

3. Start the application

The Docker Compose file contains everything needed to run the app locally.

shell
docker compose up --build

4. Open the app

Once the containers are running, visit:

shell
http://localhost:3000

5. Stop the application

shell
docker compose down

6. Remove volumes and reset the database

Use this if you want a clean local reset:

shell
docker compose down -v

CI/CD

1. Docker Build & Push

1a. Docker Build

1b. Push to ECR


2. Terraform Plan

2a. Terraform Plan Steps


3. Terraform Apply

3a. Terraform Apply Steps

3b. Post Deploy Check


4. Terraform Destroy

4a. Terraform Destroy Steps


Author

Tahmid Choudhury - DevOps Engineer