DEV Community

Cover image for Scaling & Load-balancing NodeJS Containers with Nginx
Keme Kenneth
Keme Kenneth

Posted on

Scaling & Load-balancing NodeJS Containers with Nginx

So, your NodeJS application is getting loads of requests, and it has become too much for a single server to handle. Now, you don't have a fancy AWS managed service to help you. The solution would be to manually scale your servers horizontally. Horizontally scaling is provisioning replica servers as opposed to increasing the CPU/memory combination of a single server to handle more load.

Luckily, Docker and Docker-compose with Nginx could easily get the job done for you.
Docker could easily scale your servers to any number. With Docker-compose, the job becomes even easier as you don't always have to type in a bunch docker commands.

Okay, let's assume you've used Docker to replicate your servers to 3, meaning your NodeJS application is now running in 3 replica containers. The question becomes how would each of the server know when to handle a request? In comes Nginx.

Nginx: The software load balancer, reverse proxy, web server, & content cache with the enterprise features and support you expect.

Nginx at its core is a web server.
While your 3 containers are running and not knowing when any of them should rise to the occasion and handle a request, Nginx can help with that situation with its load-balancing feature.

Load balancing refers to efficiently distributing incoming network traffic across a group of backend servers, also known as a server farm or server pool. - Nginx

Nginx in this case, will act as a proxy server, standing between your client requests and your 3 servers.

Depiction of application load balancing © phoenixNAP

When a new request comes in Nginx will accept it and route it to one of the servers. It has 3 algorithms it uses to tell which server to route traffic per time. The default of those algorithm is round-robin.

Round-robin:
First request to to server1, second request to server2, and third to server3, then repeat

Say your NodeJS server is listening on port 3000, a simple docker-compose script would look something like this:

version: '3.9'

services:
  nodeapp:
    build: .
    ports:
      - "3000"

  nginx:
    image: nginx:latest
    ports:
      - "4000:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

docker-compose.yml

The compose script builds your NodeJS app from your Dockerfile and pulls Nginx server from docker public registry. The nodeapp service is not mapped to any specific host port because only a single machine can map to a host port at every given time. But the nginx server would be taken requests on port 80, mapped to the host's 4000.

Furthermore, we added the volumes directive, to enable to us write a config file to nginx to build. This config is the crux of this setup.

events {
  worker_connections  4096;
}

http {
    server {
        listen 80;
        location / {
            proxy_pass http://nodeapp:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

nginx.conf

Nginx listens on / (home route) on port 80, then routes traffic to nodeapp on port 3000 using its proxy_pass directive.

Complete scripts including Dockerfile and simple Express app are available on my Github https://github.com/zeelz/zeelz-developer/tree/nodejs-docker-compose-nginx

Video Walkthrough

Top comments (0)