How to load Balancing Node.js apps using NGINX?

Saman Baboli
4 min readJan 26, 2018

This article will cover how to load balance Node.js applications using NGNIX.

As a first step, if you are unfamiliar with NGNIX, take a look at the article provided in the below link to learn more.

THE ISSUE

Generally, load balancing isn’t required for every application, but as your application becomes famous and popular :) it will have to handle many different traffic hits, so a single Node.js setup can’t handle that.

This is how a single Node.js setup with a NGINX reverse proxy works.

single Node.js setup with reverse proxy

SOLUTION

The diagram below shows how we can distribute requests between multiple http servers in high traffic applications.

In this example, we have 4 instances of one Node.js app that listen on different ports. You can also run your instances on other servers with different IP addresses.

This is a simple Node.js application.

const http = require('http');const hostname = '127.0.0.1';const port =  process.argv[2] || 3000;const server = http.createServer((req, res) => {res.statusCode = 200;res.setHeader('Content-Type', 'text/plain');res.end('Hello World\n');});server.listen(port, hostname, () => {console.log(`Server running at http://${hostname}:${port}/`);});

The pm2 process manager is what we use to run Node.js apps in the background.

Run application in 4 different ports like this :

pm2 start server.js -f -- 444
pm2 start server.js -f -- 445
pm2 start server.js -f -- 446
pm2 start server.js -f -- 447

Well , now we’ve 4 instances of our simple Node.js application.

Make a new file called your-domain.com.conf in /etc/nginx/conf.d/ and put the following in it:

If you have it , please open and edit it.

upstream my_http_servers {
server 127.0.0.1:444; # httpServer1 listens to port 444
server 127.0.0.1:445; # httpServer2 listens to port 445
server 127.0.0.1:446; # httpServer3 listens to port 446
server 127.0.0.1:447; # httpServer4 listens to port 447
}
server {
listen 80;
server_name your-domain.com www.your-domain.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://my_http_servers;
}
}

Upstream in NGINX defines a group of servers. Servers can listen on different ports. In addition, servers listening on TCP and UNIX-domain sockets can be mixed.

Choosing a Load Balancing Method

Load balancing in NGINX has different methods :

1 — Round-robin

In this method requests are distributed evenly across the servers with server weights taken into consideration. This method is used by default (there is no directive for enabling it).

In our Example :

upstream my_http_servers {
server 127.0.0.1:444; # httpServer1 listens to port 444
server 127.0.0.1:445; # httpServer2 listens to port 445
server 127.0.0.1:446; # httpServer3 listens to port 446
server 127.0.0.1:447; # httpServer4 listens to port 447
}

2 — least_conn

A request is sent to the server with the least number of active connections with server weights taken into consideration:

In our Example :

upstream my_http_servers {
least_conn;
server 127.0.0.1:444; # httpServer1 listens to port 444
server 127.0.0.1:445; # httpServer2 listens to port 445
server 127.0.0.1:446; # httpServer3 listens to port 446
server 127.0.0.1:447; # httpServer4 listens to port 447
}

3 — ip_hash

The server to which a request is sent is determined from the client IP address. In this case, either the first three octets of IPv4 address or the whole IPv6 address are used to calculate the hash value. The method guarantees that requests from the same address get to the same server unless it is not available.

If you use socket.io you need to use the ip_hash directive . Very important else you’ll get these “Invalid Request” errors from your app.

You can get more information about load balancing methods at nginx official web site.

Ok, let’s choose least_conn;

This is our final config file.

upstream my_http_servers {
least_conn;
server 127.0.0.1:444; # httpServer1 listens to port 444
server 127.0.0.1:445; # httpServer2 listens to port 445
server 127.0.0.1:446; # httpServer3 listens to port 446
server 127.0.0.1:447; # httpServer4 listens to port 447
}
server {
listen 80;
server_name your-domain.com www.your-domain.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://my_http_servers;
}
}

And finally restart NGINX service .

sudo service nginx restart

Conclusion

In this article we have simply built a Node.js application and distributed requests among multiple instances of it.In my next articles, I will write more about Node.js applications in production.

Last but not least, if you have any ideas about load balancing Node.js applications, please share in comments.

--

--