Skip to content

Instantly share code, notes, and snippets.

@MSK998
Last active July 1, 2021 12:30
Show Gist options
  • Save MSK998/cc91c6c150187ae46cb13df8d5a4fb9c to your computer and use it in GitHub Desktop.
Save MSK998/cc91c6c150187ae46cb13df8d5a4fb9c to your computer and use it in GitHub Desktop.
Basic PM2 Deployment

Basic PM2 Deployment

An outline on how to deploy code locally via PM2. Learn how to deploy NodeJs (or any other codebase) to a server.

Requirements

  • 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

Server Set Up

Assuming that you have created/provisioned a Linux server already:

  1. First install nvm
  2. nvm install --lts
  3. npm 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.

GitHub Repository

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.

PM2 Configuration

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.

Deploying to the Local Machine

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.

Deploying to a Remote Server

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])

Provisioning the Server(s)

While in the same directory of the config file. run the following:

  1. pm2 deploy <deployment type> setup This will clone and prepare PM2 to deploy using the codebase.
  2. pm2 deploy <deployment type> --force This will clone the repository and deploy the latest pulled code. The --force allows 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>.

Finishing Up

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

Notes on some unexpected characteristics of PM2

PM2 and Deployment Commands

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.

Ecosystem File

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.

References

  1. https://pm2.keymetrics.io/docs/usage/quick-start/
  2. https://gist.github.com/hoangmirs/b2cb60e0aa60019f0c8b13927ce9d0a2
  3. Unitech/pm2-deploy#70
  4. https://www.programmersought.com/article/85954596204/
  5. https://dev.to/goodidea/setting-up-pm2-ci-deployments-with-github-actions-1494
module.exports = {
apps : {
// Entry point of the application
script: './app.js',
// A watcher on prod isn't really necessary as
// the code should only be changed when the deployment
// is run
watch: '.'
},
deploy : {
production : {
// A password can be used but it is not recommended
key : '~/.ssh/id_rsa',
// Username of the account that owns the PM2 instance
user : 'admmsk',
// The local virtual machine hosting the application
// If running 'pm2 deploy production --force' locally,
// then change this to localhost
host : 'pm2test',
// Branch to deploy
ref : 'origin/master',
// Repository to deploy
repo : 'https://github.com/MSK998/pm2test.git',
// Where the repo files should be stored
path : './prod/',
// Commands to be run on the production server
// during pm2 deploy production setup
'pre-setup': '',
// Commands to be run on the machine deploying
'pre-deploy-local': '',
// Commands to run on the production server before the repo gets cloned
'pre-deploy': 'hostname',
// Commands to run after the new code has been deployed
'post-deploy' : 'npm install && pm2 reload ecosystem.config.js',
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment