πŸš€ Deploying a Node.js CRUD App on AWS with Terraform

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5175

    #1

    πŸš€ Deploying a Node.js CRUD App on AWS with Terraform

    Managing cloud infrastructure manually can quickly become messy. Terraform allows us to define infrastructure as code (IaC), making deployments repeatable, version-controlled, and automated.


    In this guide, we’ll build a Node.js CRUD API (with Express + MongoDB) and deploy it to AWS ECS Fargate using Terraform.





    🧩 What We’re Building

    • A RESTful Todo API (CRUD endpoints with Express + MongoDB).
    • Dockerized app pushed to Amazon ECR.
    • AWS ECS Fargate service running containers in a managed VPC.
    • Application Load Balancer (ALB) to expose the service.
    • Secrets Manager for storing MongoDB credentials securely.
    • CloudWatch Logs for centralized logging.


    Here’s the final architecture:






    Client β†’ ALB β†’ ECS (Fargate Task) β†’ MongoDB (Atlas/Local)
    ↑
    CloudWatch (logs)










    πŸ› οΈ Tech Stack

    Backend
    • Node.js + Express
    • MongoDB + Mongoose
    • CORS + dotenv


    Infrastructure
    • Docker (containerization)
    • Terraform (IaC)
    • AWS ECR (image registry)
    • AWS ECS Fargate (orchestration)
    • AWS ALB (load balancing)
    • AWS Secrets Manager (secure DB credentials)
    • AWS IAM + Security Groups





    πŸ“ Project Structure

    Your project is split into two main parts: app code and infra code.






    manthanank-nodejs-terraform/
    β”œβ”€β”€ server.js # Express entry
    β”œβ”€β”€ Dockerfile # Build container
    β”œβ”€β”€ config/db.js # Mongo connection
    β”œβ”€β”€ controllers/todoController.js
    β”œβ”€β”€ models/Todo.js
    β”œβ”€β”€ routes/todoRoutes.js
    β”œβ”€β”€ terraform/ # Infrastructure as Code
    β”‚ β”œβ”€β”€ vpc.tf # VPC + networking
    β”‚ β”œβ”€β”€ ecs.tf # ECS cluster/service
    β”‚ β”œβ”€β”€ ecr.tf # ECR repo
    β”‚ β”œβ”€β”€ iam.tf # IAM roles/policies
    β”‚ β”œβ”€β”€ security.tf # Security groups
    β”‚ β”œβ”€β”€ logs.tf # CloudWatch logs
    β”‚ β”œβ”€β”€ secrets.tf # Secrets Manager
    β”‚ β”œβ”€β”€ variables.tf # Config vars
    β”‚ β”œβ”€β”€ outputs.tf # Useful outputs
    β”‚ └── provider.tf # AWS provider setup










    πŸ“ Step 1 β€” Build the Node.js API

    Our CRUD endpoints live under /api/todos.

    Example schema:






    const todoSchema = new mongoose.Schema({
    title: { type: String, required: true, trim: true },
    description: { type: String, default: "" },
    completed: { type: Boolean, default: false },
    createdAt: { type: Date, default: Date.now },
    });







    Start locally:






    npm install
    npm run dev







    Test:






    curl http://localhost:5000/api/todos










    πŸ“¦ Step 2 β€” Dockerize the App

    Dockerfile:






    FROM node:18-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci --only=production
    COPY . .
    ENV PORT=5000
    EXPOSE 5000
    CMD ["node", "server.js"]







    Build locally:






    docker build -t nodejs-todo-api .
    docker run -p 5000:5000 -e MONGO_URI=your_mongo_uri nodejs-todo-api










    ☁️ Step 3 β€” Terraform AWS Infrastructure

    Initialize





    cd terraform
    terraform init







    Key Resources

    • ECR β€” stores our container image (ecr.tf).
    • ECS Fargate Service β€” runs containers (ecs.tf).
    • ALB + Target Group β€” load balancing (ecs.tf).
    • VPC + Subnets β€” networking (vpc.tf).
    • IAM Roles β€” ECS execution permissions (iam.tf).
    • Secrets Manager β€” injects MONGO_URI securely (secrets.tf).
    • CloudWatch Logs β€” for application logs (logs.tf).





    🐳 Step 4 β€” Push Image to ECR

    1. Create the repo:




    terraform apply -target=aws_ecr_repository.app -auto-approve






    1. Build & push:




    AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    REGION=ap-south-1
    REPO=$AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/node-crud-app
    IMAGE_TAG=v1

    docker build -t node-crud-app:$IMAGE_TAG .
    aws ecr get-login-password --region $REGION | \
    docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com
    docker tag node-crud-app:$IMAGE_TAG $REPO:$IMAGE_TAG
    docker push $REPO:$IMAGE_TAG










    πŸš€ Step 5 β€” Deploy with Terraform

    Apply the full infra:






    terraform apply







    Grab the output:






    terraform output alb_dns







    Test:






    curl http:///api/todos










    πŸ”„ Step 6 β€” Deploy Updates

    1. Build and push a new image with IMAGE_TAG=v2.
    2. Update variables.tf β†’ image_tag = "v2".
    3. Run:




    terraform apply -var="image_tag=v2"







    ECS performs a rolling update behind the ALB.





    πŸ“Š Monitoring & Logs

    • CloudWatch Logs: All app logs stream automatically.
    • ALB Health Checks: Ensure tasks are healthy.
    • Troubleshooting: Check ECS task logs in CloudWatch if service won’t start.





    πŸ”’ Security Best Practices

    • Use private subnets + NAT Gateway in production.
    • Restrict Secrets Manager IAM role to a single secret ARN.
    • Use immutable image tags (v1, v2) instead of latest.
    • Enable HTTPS on ALB with ACM certificates.





    🎯 Conclusion

    With just a few .tf files, we’ve automated provisioning of:
    • Containerized Node.js API
    • Secure AWS networking & IAM
    • Load-balanced ECS service
    • Secrets and logs managed by AWS


    This approach scales to any microservice β€” just add more services, modules, or CI/CD pipelines.





    ✨ Pro tip: Next step, integrate GitHub Actions or GitLab CI to automatically build/push Docker images and run terraform apply for full CI/CD.







    More...
Working...