An outline on how to deploy code locally via PM2. Learn how to deploy NodeJs (or any other codebase) to a server.
- A codebase to run on PM2
- A server to deploy your code to, in this case im just using a VM running Ubuntu:20.04
Assuming that you have created/provisioned a Linux server already:
- First install nvm
nvm install --ltsnpm install -g pm2
Once all of these commands have been run you should have a working install of PM2 running on your preferred flavour of Linux.
Now that the server is set up make sure the repository that your code is in, has been set up. Once it has been set up take a note of your GitHub clone URL. For this example, we can use: https://github.com/MSK998/pm2test. We will cover the the various ways to clone the code further on in the guide.
In order to deploy using PM2 we need to create a configuration as code (CaC). To generate a sample config, run pm2 ecosystem. An ecosystem.config.js file will be generated. Because this is a basic deployment, much of what is in this file is a little bit redundant.
To deploy to the local server(the Ubuntu server we set up) we need to change a few values in the default file. Most importantly, we need to change the host. In a production environment PM2 can be used as a deployment server, i.e. the PM2 server that is managing the deployment doesn't actually deploy the code itself.
The most important props that need to be changed are the user and host props. These should be changed to the local user that should be running the deployment, and the host should be changed to localhost. PM2 will now run deployments on the local machine with this config change.
Other things of note to change are the repo props, this should be changed to the repo address. Both HTTPS and SSH can be used to clone the repository. If using SSH then the server public key should be added to the deploy keys (or using the user SSH keys on the user account).
Finally, make sure to update the script prop to be the entrypoint of the application, so if your Node app starts a server using server.js then set script to that.
A great example to take from is the sample config that is generated by PM2. All server IPs that are listed (if there are multiple the IPs can be added to an array [ip 1, ip 2, ip 3])
While in the same directory of the config file. run the following:
pm2 deploy <deployment type> setupThis will clone and prepare PM2 to deploy using the codebase.pm2 deploy <deployment type> --forceThis will clone the repository and deploy the latest pulled code. The--forceallows the user to run the most up-to-date code without any of the git error messages.
The deployment type is outlined in your config file, in the example attached you would add production to the command where <deployment type>.
Once the deploy has been completed if you run pm2 l you should be able to see the newly deployed instance of your appliation.
Notes on some unexpected characteristics of PM2
One thing that I found out is that pm2 doesn't run an interactive shell when running these scripts. Because of the way the default .bashrc file works, by default it wont load any environment variables. This will break NVM and thus the server will not be able to find the NodeJS binary when deploying.
To fix this rearrange the .bashrc file to the following, this will allow NVM variables to be set before the check for an interactive terminal is done
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Doing this will ensure that the PM2 shell can access the NodeJs Binary.
While messing around with PM2 and the deployments settings that can be changed, it is important to include the ecosystem file in the root of the project directory in GitHub. When spinning up instances of your production code, the PM2 instance that is installed on the production server uses the ecosystem file to start, stop and reload apps. If the file isnt present, the deployment will fail. Note that the testing repository has this ecosystem file checked into git.