Bit of an old question this but I recently had to do this and I feel like a more complete answer might be helpful to anyone who lands from google like I did. I'm assuming you're on a smaller set up not using nginx as a load balancer for multiple servers, and that your application is stateless per the PM2 documentation. If it isn't stateless you can run into problems with cluster mode.
Also learned that pm2 itself provides built-in load balancer, why
should i use nginx then?
Firstly both PM2 and Nginx can operate as load balancers. It is often said that NodeJS is "single-threaded" so can only utilize one CPU core at a time - PM2 in cluster mode runs multiple instances of the same NodeJS app under a master process, allowing you to utilize more cores on the host machine. PM2 does this without requiring each instance of the app run on a different port (although it could) or IP (which I'll get to).
You can initialize PM2 in cluster mode with something like this: pm2 start -i NUMBER_OF_CORES(e.g 2) npm --name APP_NAME -- run start
Meanwhile, Nginx can also load balance NodeJS apps - however it will do so using the upstream block. This takes different host machines and different IPs and might look something like this:
upstream app_servers {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3002;
}
server {
listen 80 ;
gzip on;
root /var/www/html;
index index.html index.htm;
server_name FRONTURL;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://app_servers;
}
}
You can see the difference between these two options is primarily that nginx allows you to load balance across multiple IPs, ports and servers, whilst PM2 is a quick and simple load balancer for apps sharing a CPU resource. You could try to use both by using nginx to load balance requests across VMs, and then PM2 to ensure each machine is using its cores completely, I suppose.
Now, despite all of this, the main way you will use nginx in-front of PM2 in cluster mode is if you are using it to serve static content from a client side rendered app (e.g react) and communicating with a nodejs backend through HTTP calls where you want to load balance across CPU cores. In this case Nginx would serve as 1) A static content server from the frontend 2) A reverse proxy to communicate with the backend running in cluster mode. In this case your nginx config might look like this:
{
listen 80 ;
gzip on;
root /var/www/html;
index index.html index.htm;
server_name FRONTURL;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://localhost:NODEJS_PORT/;
}
}
And, of course, you could proxy pass a server side rendered app in a similar fashion by tweaking the location block ;)