This guide helps you rebuild your project in 2 stages:
- Stage 1: Reverse Proxy only
- Stage 2: Add Load Balancing
Use Stage 1 first, then move to Stage 2.
docker-compose.ymlapp/nginx/nginx.conf
- Docker Desktop installed
- Docker Compose available
Before Stage 1 or Stage 2, create these files inside app/.
const express = require("express");
const os = require("os");
const app = express();
const PORT = 3000;
const INSTANCE = process.env.INSTANCE_NAME || os.hostname();
app.get("/", (req, res) => {
res.send(`Hello World from ${INSTANCE}`);
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT} - ${INSTANCE}`);
});{
"name": "lb-demo",
"version": "1.0.0",
"main": "server.js",
"dependencies": {
"express": "^4.18.2"
}
}FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Why this is required:
- Your compose services use
build: ./app. - So Docker needs
app/Dockerfileto build the app image. - Nginx does not need a Dockerfile in this setup because it uses
nginx:latestdirectly.
In this stage, Nginx forwards requests to one backend app.
Replace docker-compose.yml with:
version: "3.9"
services:
app1:
build: ./app
environment:
- INSTANCE_NAME=App-1
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app1Replace nginx/nginx.conf with:
events {}
http {
server {
listen 80;
location / {
proxy_pass http://app1:3000;
}
}
}docker compose up --buildOpen:
Expected:
- You always see response from
App-1
This proves Reverse Proxy is working.
Now upgrade from one backend to three backends.
Replace docker-compose.yml with:
version: "3.9"
services:
app1:
build: ./app
environment:
- INSTANCE_NAME=App-1
app2:
build: ./app
environment:
- INSTANCE_NAME=App-2
app3:
build: ./app
environment:
- INSTANCE_NAME=App-3
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app1
- app2
- app3Replace nginx/nginx.conf with:
events {}
http {
upstream backend {
server app1:3000;
server app2:3000;
server app3:3000;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}docker compose up --buildRefresh this URL multiple times:
Expected:
- You should see different instance names (
App-1,App-2,App-3) over multiple requests.
This proves Load Balancing is working.
- Reverse Proxy: Nginx accepts client request and forwards to backend service.
- Load Balancing: Nginx distributes requests across multiple backend services.
If you want a clean restart:
docker compose down -v
docker compose up --build