https://roadmap.sh/projects/multi-container-service
A minimal, unauthenticated REST API for managing a todo list, built with Node.js, Express, Mongoose and MongoDB.
This project demonstrates:
- Basic CRUD API
- MongoDB persistence
- Containerization with Docker & docker-compose
- Infrastructure as Code (Terraform + Ansible)
- CI/CD deployment (GitHub Actions)
- (Bonus) Nginx reverse proxy setup
| Method | Endpoint | Description | Request Body (JSON) |
|---|---|---|---|
| GET | /todos |
List all todos | — |
| POST | /todos |
Create a new todo | { "title": "Buy milk", "completed": false } |
| GET | /todos/:id |
Get one todo by ID | — |
| PUT | /todos/:id |
Update todo (full or partial) | { "title": "...", "completed": true } |
| DELETE | /todos/:id |
Delete a todo | — |
Note: No authentication / authorization is implemented.
- Runtime Node.js
- Framework Express
- Database MongoDB
- ODM Mongoose
- Dev tooling nodemon
- Container Docker + docker-compose
- IaC Terraform (server), Ansible (configuration)
- CI/CD GitHub Actions
- Bonus Nginx (reverse proxy)
todo-api/
├── src/
│ ├── controllers/
│ │ └── todo.controller.js
│ ├── config/
│ │ └── db.js
│ ├── routes/
│ │ └── todos.routes.js
│ ├── app.js # or index.js
│ └── index.js
├── .dockerignore
├── .gitignore
├── Dockerfile
├── docker-compose.yml
├── terraform/
│ ├── main.tf
│ ├── variables.tf
│ └── ...
├── ansible/
│ ├── playbook.yml
│ └── roles/
├── .github/
│ └── workflows/
│ └── deploy.yml
└── README.md
# 1. Start MongoDB + API
docker compose up -d
# 2. With hot-reload (recommended for development)
docker compose -f docker-compose.yml -f docker-compose.dev.yml upAPI will be available at: http://localhost:3000
- Docker 20.10+
- Docker Compose v2
- (optional) Node.js 18+ & npm/yarn/pnpm — for local non-docker development
| Service | Port mapping | Purpose | Persisted? |
|---|---|---|---|
| api | 3000 → 3000 | Node.js / Express application | — |
| mongo | — | MongoDB database | Yes |
| mongo-express | 8081 → 8081 (opt.) | Web UI for browsing MongoDB | — |
| nginx | 80 → 80 (bonus) | Reverse proxy (bonus) | — |
+-------------------+ +---------------------+ +-----------------+
| GitHub | | Remote VM | | Docker Host |
| (main branch) | → | (DigitalOcean / | → | • api |
| → GitHub Actions | | AWS / ...) | | • mongo |
+-------------------+ | • Docker + Compose | | • nginx (bonus)|
+---------------------+ +-----------------+
↑
Terraform (create VM)
↑
Ansible (setup)
-
Create infrastructure
cd terraform terraform init terraform apply -
Configure server & deploy first version
cd ansible ansible-playbook -i inventory.yml playbook.yml -
Future changes → just push to
main→ GitHub Actions handles build & deploy
Typical workflow triggers on:
- push to
main - pull request to
main
Steps usually include:
- lint & test (if you added tests)
- build & push Docker image to Docker Hub / GHCR
- SSH into server
docker compose pull && docker compose up -d
Secrets needed in Multi-Container-Application settings:
SSH_PRIVATE_KEYSERVER_IPorHOSTDOCKERHUB_USERNAME/DOCKERHUB_TOKEN(if using Docker Hub)
- Point domain A record → server public IP
- Install certbot inside nginx container or on host
- Obtain Let's Encrypt certificate
- Update nginx config to use SSL
Or use a managed solution (Cloudflare, Traefik, Caddy, etc.)
- Add input validation (Joi / Zod / express-validator)
- Add basic tests (Jest + supertest)
- Implement health-check endpoint
/health - Add API documentation (Swagger / Redoc)
- Add rate limiting
- Add simple authentication (JWT / API key)
- Use MongoDB transactions (if needed)
- Add logging (winston / pino)
- Add environment-based configuration (dotenv / convict)
MIT