In the past, on my server I’ve installed Fossil, Syncthing, Bitwarden, Inlets. All these require some form of Process Management. These programs / processes / services need to be always running, so they are restarted in case they get terminated. Also, on a system restart these need to start up automatically.
I’ve mostly used Systemd or Supervisor to all these things.
However, I recently came across PM2 and I was really blown out of my mind as to how simple it was to set it up.
It’s a NodeJS application, so that needs to be there.
Installation
Installing it globally means to run –
npm install -g pm2
Of course it works seamlessly with Node applications
Starting applications
So to start a Node application in the background, all we need to do is –
pm2 start app.js
But to run a ruby application is as simple! So to run a rails
application –
pm2 start rails
For that matter, to run a shell script would be –
pm2 start bashscript.sh
By default, PM2 process takes the name of the file that is run. To explicitly assign a name for a rake
task would be –
pm2 start "bundle exec rake app:notifications" --name "app notifications"
Additionally, there are a whole lot of other options that can be passed in.
Once the processes are running, entering pm2 status
gives us a very nice output.
Managing processes
To manage the processes is also extremely simple.
pm2 restart app_name pm2 reload app_name pm2 stop app_name pm2 delete app_name
And even to get a realtime dashboard of all processes running, the command to run is pm2 monit
Managing multiple applications
To manage many applications from one place, we can create an ecosystem
file by running –
pm2 ecosystem
This creates an ecosystem.config.js
file which looks like this –
module.exports = { apps : [{ name: "app", script: "./app.js", env: { NODE_ENV: "development", }, }, { name: 'worker', script: 'worker.js' }] }
Since I wanted a single place to manage everything from, that’s what I did.
To start pm2
with this ecosystem.config.js
–
pm2 start ~/pm2/ecosystem.config.js
Reading environment variables from outside the ecosystem file
I had another challenge though – for one of the applications I needed to have an environment variable set and I didn’t want that in the ecosystem.config.js
file. I wanted it in a separate file from which it could be read.
Since the ecosystem.config.js
is a simple javascript file, we can add some code for that –
const fs = require('fs'); const path = require('path'); const pathToTokenFile = path.join('/path/to/token_file'); const appToken = () => { const token = fs.readFileSync(pathToTokenFile, 'utf8');; return token; } module.exports = { apps : [{ name: "app", script: "./app.js", env: { NODE_ENV: "development", AUTHTOKEN: appToken() }, }, { name: 'worker', script: 'worker.js' }] }
Start applications on boot
To create a script which will start all my applications at boot
time –
pm2 startup
This will give an output which which is basically a command that I need to execute manually
sudo env PATH=$PATH:/path/to/node /path/to/pm2 startup systemd -u myusername --hp /my/home/directory
Essentially this command will create a systemd
service which will start PM2 automatically and then PM2 will start all the applications.
And just in case we want to remove it from startup.
pm2 unstartup systemd
PM2 is truly an amazing piece of software!
Rarely have I seen a software which does so many complex things in such a simple manner. Kudos to them!