This repository demonstrates a production-style architecture using:
- Node.js (Express)
- Nginx as Reverse Proxy
- Horizontal Scaling (Multiple Instances)
- Docker & Docker Compose
- Load Testing using Autocannon
The goal of this project is to deeply understand:
- How Nginx works as a reverse proxy
- How Docker networking works
- How horizontal scaling improves performance
- How failover behaves when instances go down
- When to rebuild images vs reuse containers
Client
↓
Nginx (port 8000)
↓
app1 | app2 | app3 (Node containers)
Nginx distributes traffic across multiple Node instances.
- Node.js 22 (Alpine)
- Express
- Nginx
- Docker
- Docker Compose
- Nodemon (dev only)
- Autocannon (load testing)
- Reverse proxy configuration
- Docker internal networking
- Service name DNS resolution
- Horizontal scaling
- Failover testing
- Dev vs Production Docker setups
- Load testing and performance comparison
.
├── app.js
├── package.json
├── Dockerfile
├── Dockerfile.dev
├── docker-compose.dev.yml
├── docker-compose.prod.yml
├── nginx.conf
└── README.md
git clone <your-repo-url>
cd ngnixpracStart the development environment:
npm run docker:devIf you changed dependencies or Dockerfile:
npm run docker:dev:buildTo stop everything:
npm run docker:dev:downhttp://localhost:8000
Each refresh should show different INSTANCE_ID, proving load balancing works.
Example response:
{
"message": "Node js server running ngnix 🚀🚀🚀",
"instance": "2"
}Start production container:
npm run docker:prodAccess:
http://localhost:3000
Production image:
- No nodemon
- Uses
npm install --production - Restart policy enabled
docker compose updocker compose up --builddocker compose downdocker compose stop app1Install autocannon globally (optional):
npm install -g autocannonnpx autocannon -c 100 -d 15 http://localhost:8000npx autocannon -c 100 -d 15 http://localhost:3000With 1 instance:
- ~13k req/sec (baseline)
With 3 instances:
- Near-linear scaling under Nginx
Stop one container during load:
docker compose -f docker-compose.dev.yml stop app2Observe:
- Traffic reroutes automatically
- System remains operational
- Throughput decreases proportionally
events {}
http {
upstream backend {
server app1:3000;
server app2:3000;
server app3:3000;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}localhostinside Docker refers to the container itself- Docker services communicate via internal DNS
- Horizontal scaling improves throughput
- Nginx handles connection management efficiently
docker compose upvsup --build- Dev vs Production image separation
This repository demonstrates practical backend infrastructure knowledge including:
- Reverse proxy architecture
- Container orchestration fundamentals
- Load balancing
- High availability testing
- Performance benchmarking