If you’ve ever built a full-stack app and asked yourself:
“How do I deploy this professionally in production with DevOps best practices?”
This case study walks through exactly how I achieved that — step-by-step — including the challenges, mistakes, and real fixes.
Project Overview I built and deployed a production-grade full-stack note-taking application called Notify.
Technologies involved:
- React + Vite for the frontend
- Node.js + Express for the backend
- MongoDB as the database
- Docker & Docker Compose for containerization
- AWS EC2 for hosting
- GitHub Actions CI/CD for automated deployment
The goal: Push code → App auto-deploys to AWS → No manual server changes
- Phase 1 — Dockerizing the MERN Application The first step was packaging each part of the application into its own container.
Backend Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["npm", "start"]
Frontend Dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
The frontend is built and then served using Nginx — making it production-ready.
- Phase 2 — Docker Compose for Multi-Service Orchestration To run all three containers together and ensure they communicate properly:
services:
mongo:
image: mongo:6
container_name: mongo-db
ports:
- "27017:27017"
restart: always
backend:
build: ./backend
env_file: ./backend/.env
environment:
- MONGODB_URI=mongodb://mongo:27017/notifydb
ports:
- "5000:5000"
depends_on:
- mongo
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
Key insight:
The backend connects to MongoDB using the container name mongo, not localhost.
Phase 3 — Deploying to AWS EC2
I launched an Amazon Linux 2023 EC2 instance and prepared it for containerized deployment.Installed Docker
Installed Docker Compose
Added ec2-user to Docker group
Security groups configured correctly
Opened inbound ports:
- 80 → Web traffic
- 5000 → Backend API
- 22 → SSH Access
- Then deployed:
- git clone https://github.com/emperorbj/notify.git
- cd notify
- docker compose up -d --build
🎉 Site instantly reachable via:
- Phase 4 — Enabling CI/CD With GitHub Actions The goal was zero manual deployments after setup.
📌 Every time I push to main:
- EC2 pulls new code
- Docker rebuilds
- Containers restart automatically
- Old images removed
GitHub Actions workflow:
name: Deploy to EC2
on:
push:
branches: ["main"]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: SSH Agent
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add Known Hosts
run: ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts
- name: Deploy Over SSH
run: |
ssh ec2-user@${{ secrets.EC2_HOST }} << 'EOF'
cd ~/notify
git pull origin main
docker compose down || true
docker compose up -d --build
docker image prune -f
EOF
Real-World Problems I Had to Solve
This wasn’t smooth — and that’s exactly the valuable part.
- Problems + Fixes: Backend couldn’t connect to MongoDB → switched URI to container name
Deployment failing due to wrong Docker version → updated Docker + enabled compose
Frontend wouldn’t load → exposed port 80, not Vite’s local 5173
SSH denied → fixed key pairing and GitHub secrets
Docker commands failing → added EC2 user to Docker group
Every issue taught me lessons developers don’t learn until production ✨
You can watch the process here :
https://www.loom.com/share/897f49af1b274e3fba6921c842d0653b
🎯 What This Project Proved
I now understand:
🔥 Container orchestration with Docker
🔥 Cloud deployment using AWS EC2
🔥 Networking between services in production
🔥 Continuous Deployment pipelines
🔥 Debugging real infrastructure failures
This project took me from “I can code this” to:
✅ “I can run this in production — automatically.”
✅ Final Result ✅
✔ Full MERN App running live on AWS
✔ 100% Dockerized microservices
✔ Push-to-deploy automation
✔ Secure, scalable architecture
✔ Excellent DevOps experience gained
This is now a foundation I can reuse for multiple future projects
Top comments (0)