A production-ready Node.js + Express + MongoDB server with fully automated CI/CD — push to main and it deploys itself to an Azure VM via SSH, Docker, and GitHub Actions.
┌─────────────┐ push to main ┌──────────────────┐
│ Developer │ ──────────────────────▶│ GitHub Actions │
└─────────────┘ └────────┬─────────┘
│ SSH
▼
┌──────────────────┐
│ Azure VM │
│ ┌──────────────┐ │
│ │ Docker │ │
│ │ ┌─────────┐ │ │
│ │ │ Node.js │ │ │
│ │ │ App │ │ │
│ │ └─────────┘ │ │
│ └──────────────┘ │
└──────────────────┘
│
▼
┌──────────────────┐
│ MongoDB Atlas │
└──────────────────┘
- Express 5 REST API with TypeScript
- MongoDB integration via Mongoose
- Multi-stage Docker build — lightweight production image using
node:22-alpine - GitHub Actions CI/CD — auto-deploys on every push to
main - SSH-based deployment to an Azure VM using
appleboy/ssh-action - Docker Compose for easy container orchestration
- Environment variable management via
dotenvand GitHub Secrets
| Layer | Technology |
|---|---|
| Runtime | Node.js 22 (Alpine) |
| Language | TypeScript 5 |
| Framework | Express 5 |
| Database | MongoDB (Mongoose 9) |
| Containerization | Docker + Docker Compose |
| CI/CD | GitHub Actions |
| Hosting | Azure VM |
.
├── .github/workflows/
│ └── deploy.yaml # GitHub Actions CI/CD pipeline
├── db.ts # MongoDB connection helper
├── server.ts # Express application entry point
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Container orchestration
├── tsconfig.json # TypeScript configuration
├── package.json # Dependencies & scripts
├── .env # Environment variables (not committed)
└── .gitignore
- Node.js v22+
- Docker & Docker Compose
- A MongoDB instance (e.g. MongoDB Atlas)
git clone https://github.com/Sahilagarwal623/deployment-automation-github-actions.git
cd deployment-automation-github-actionsCreate a .env file in the project root:
PORT=8000
MONGO_URL=mongodb+srv://<username>:<password>@<cluster>.mongodb.net/<dbname>npm install
npm run devThe server will start with hot-reloading via nodemon.
docker compose up -d --buildThe app will be available on http://localhost:8080.
The GitHub Actions workflow (.github/workflows/deploy.yaml) automates deployment on every push to main:
- Checkout — pulls the latest code
- SSH into Azure VM — connects using secrets
- Pull latest changes — runs
git pullon the server - Inject environment variables — writes secrets to
.env - Rebuild & restart — runs
docker compose up -d --build
| Secret | Description |
|---|---|
SSH_HOST |
Azure VM public IP or hostname |
SSH_USERNAME |
SSH username (e.g. azureuser) |
SSH_KEY |
Private SSH key for authentication |
PORT |
Application port (e.g. 8000) |
MONGO_URL |
MongoDB connection string |
| Script | Command | Description |
|---|---|---|
npm run dev |
nodemon + ts-node |
Start dev server with hot reload |
npm run build |
tsc |
Compile TypeScript to dist/ |
npm start |
node dist/server.js |
Run production build |
The Dockerfile uses a multi-stage build for an optimized production image:
- Stage 1 (Builder) — installs all dependencies, compiles TypeScript
- Stage 2 (Runner) — copies only compiled JS + production dependencies
This keeps the final image small and free of dev tooling.
ISC