Express + GraphQL backend for the Milestone.
This backend is containerized with:
Dockerfile: production-ready Node.js image builddocker-compose.yml: multi-container local stack (frontend + backend + MongoDB).dockerignore: optimized Docker build context
The setup is structured for clean local development and predictable deployment behavior.
- Docker Desktop (macOS/Windows) or Docker Engine + Compose plugin (Linux)
- Port
9000available for backend - Port
27017available for MongoDB - Port
3000available for frontend
-
Create local environment file:
cp .env.example .env
-
Start full stack in detached mode:
docker compose up -d --build
-
Verify services:
docker compose ps
-
Verify API health:
curl http://localhost:9000/api/health
-
Stop services:
docker compose down
-
Stop and remove DB volume too (destructive):
docker compose down -v
- Built from local
Dockerfile - Runs as non-root
nodeuser - Exposes port
9000 - Depends on healthy MongoDB container
- Persists runtime-generated files:
./logs->/app/logs./uploads->/app/uploads
- Uses official
mongo:7image - Exposes port
27017 - Stores data in named volume
mongo_data - Includes healthcheck used by backend dependency ordering
- Built from
../Milestone-frontend/Dockerfile - Serves optimized Vite output via Nginx
- Exposes port
3000on host (container port80) - Uses build arg
VITE_BACKEND_URL(defaulthttp://localhost:9000)
Core variables used by the backend:
NODE_ENVPORTFRONTEND_ORIGINSESSION_SECRETMONGO_URL
Optional integration variables:
EMAIL_SERVICE,EMAIL_USER,EMAIL_PASSCLOUDINARY_CLOUD_NAME,CLOUDINARY_API_KEY,CLOUDINARY_API_SECRETRAZORPAY_KEY_ID,RAZORPAY_KEY_SECRET
Use .env.example as the source of truth for names and defaults.
docker compose build backenddocker compose logs -f backenddocker compose logs -f mongodocker compose logs -f frontenddocker compose exec backend sh- Replace
SESSION_SECRETbefore any non-local deployment. - Replace default MongoDB credentials in
.env. - Keep
.envout of version control. - Restrict CORS origin to your actual frontend domain in production.
- Check backend logs:
docker compose logs backend - Confirm
MONGO_URLpoints tomongoservice hostname - Confirm mongo healthcheck passes:
docker compose ps
- Change host mapping in
docker-compose.yml(for example9001:9000) - Restart stack:
docker compose up -d --build
docker compose down -v
docker compose up -d --buildThis project supports direct VM deployment without pushing images to Docker Hub.
When you push to main, GitHub Actions connects to your VM over SSH, pulls latest
backend + frontend code, and runs:
docker compose up -d --build --remove-orphans.github/workflows/deploy-vm.yml
scripts/deploy-vm.sh
VM_HOST: Public IP or hostname of your VMVM_USER: SSH user on VMVM_SSH_KEY: Private key content (PEM/OpenSSH) used by GitHub ActionsVM_BACKEND_PATH: Absolute backend repo path on VMVM_FRONTEND_PATH: Absolute frontend repo path on VM
Backend and frontend should exist as two git repos on VM. Example:
/opt/apps/m-backend
/opt/apps/Milestone-frontend
The backend compose file builds frontend with ../Milestone-frontend, so these paths must
be sibling-compatible in your VM layout.
- Install Docker and Docker Compose plugin.
- Clone backend and frontend repos on VM.
- Create backend
.envfile in backend repo path. - Ensure VM user can run Docker (
docker psworks without sudo). - Push to
mainor run workflow manually from GitHub Actions.
You can run the same deployment manually:
cd /opt/apps/m-backend
./scripts/deploy-vm.sh /opt/apps/Milestone-frontend main