Skip to content

Repository files navigation

MEAN CRUD App - Dockerized Full-Stack Deployment

MEAN CRUD app (MongoDB, Express, Angular 15, Node.js) with Docker, Nginx reverse proxy, and CI/CD workflow for containerized deployment.

Architecture

  • Angular static build served by Nginx on port 80
  • Nginx proxies /api to the Node/Express backend
  • MongoDB runs as a container via Docker Compose
  • Health checks on all services for zero-downtime updates
  • Graceful shutdown handling prevents data loss during restarts
  • MongoDB persistence via named Docker volume

Local development (non-containerized)

Backend

cd backend
npm install
node server.js

Frontend

cd frontend
npm install
ng serve --port 8081

Navigate to http://localhost:8081/. The dev server proxies /api to http://localhost:8080 via frontend/proxy.conf.json.

Containerization

Dockerfiles are in backend/Dockerfile and frontend/Dockerfile. Nginx config is in frontend/nginx.conf.

Build and run locally with Docker Compose

copy .env.example .env

Update DOCKERHUB_USERNAME in .env.

docker compose build
docker compose up -d

App will be available at http://localhost/.

Database persistence

MongoDB data is stored in the mongo_data named volume, which persists across container restarts. To preserve data during upgrades, never use docker compose down (this removes volumes). Instead:

docker compose stop
docker compose up -d

Or upgrade safely without stopping:

docker compose pull
docker compose up -d

Cloud VM setup (Ubuntu on AWS)

  1. Create an Ubuntu VM (t2.micro or similar) and open inbound port 80.
  2. Install Docker and Docker Compose plugin:
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
  1. Create an app directory and copy files:
sudo mkdir -p /opt/mean-app
sudo chown $USER:$USER /opt/mean-app

Copy these files into /opt/mean-app on the VM:

  1. Make deploy script executable:
chmod +x /opt/mean-app/deploy.sh
  1. Run the stack:
cd /opt/mean-app
bash deploy.sh

Zero-downtime deployments

The application uses:

  • Health checks on all services (MongoDB, backend, frontend) to ensure containers are fully ready before accepting traffic
  • Graceful shutdown (30-second stop_grace_period) to allow in-flight requests to complete
  • Service dependencies configured to only start containers when their dependencies are healthy

The deploy.sh script:

  1. Pulls latest images
  2. Updates containers with docker compose up -d (no downtime)
  3. Waits for services to pass health checks before declaring success

To manually deploy safely:

cd /opt/mean-app
bash deploy.sh

DO NOT use docker compose down (removes volumes and causes data loss). Always use:

docker compose pull
docker compose up -d

CI/CD (GitHub Actions)

Workflow file: .github/workflows/ci-cd.yml

Required GitHub secrets

  • DOCKERHUB_USERNAME
  • DOCKERHUB_TOKEN
  • VM_HOST
  • VM_USER
  • VM_SSH_KEY

On each push to main, the workflow:

  1. Builds and pushes updated images to Docker Hub
  2. SSHes into the VM and runs deploy.sh for zero-downtime updates
  3. Automatically cleans up dangling images

Screenshots

CI/CD and Docker Image Build

Application deployment and working UI

Nginx setup and infrastructure details

  • Nginx reverse proxy config

nginx.conf: frontend/nginx.conf

  • VM/container status

VM status screenshot

Nginx reverse proxy

Nginx runs inside the frontend container and serves the Angular build. It proxies API requests under /api to the backend container. The reverse proxy configuration is in frontend/nginx.conf.

Notes

  • Backend reads MongoDB URL from MONGO_URI and defaults to mongodb://localhost:27017/dd_db if not set.
  • Frontend uses a relative API base path, so it works behind the Nginx proxy.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages