Skip to content

Instantly share code, notes, and snippets.

@leeroybrun
Forked from hoangmirs/deploy-pm2.md
Last active June 7, 2024 21:25
Show Gist options
  • Save leeroybrun/842107b08881d2f864345ffd2e5e58de to your computer and use it in GitHub Desktop.
Save leeroybrun/842107b08881d2f864345ffd2e5e58de to your computer and use it in GitHub Desktop.
Deploy pm2 guide

1. Preparing the server

Install git

sudo apt install git-all

Generate a new deploy key

https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys

ssh-keygen -t rsa -b 4096 -C "deploy"

Save the key to a file identifying it clearly, like ~/.ssh/github_repoxyz_deploy_key.

Add an alias to use the new deploy key :

vi ~/.ssh/config
Host github.com-repo-xyz
        Hostname github.com
        IdentityFile=/home/user/.ssh/github_repoxyz_deploy_key

Copy the key and add it to the deploy keys on the Github repo :

cat ~/.ssh/github_repoxyz_deploy_key.pub

Add your local SSH public key to server

Insert your local SSH public key to .ssh/authorized_keys on server. If server don't has this file, let create one :

cd
mkdir ~/.ssh
touch ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Install directory & rights

We will run PM2 and node as www-data so that it does not have sudo rights and it is more safe.

We have to choose a directory to store our apps and Node/packages.

In the below commands we will use /var/www.

Prepare the install dir

Give it the correct rights :

sudo chown -R www-data:www-data /var/www
sudo chmod -R 775 /var/www
sudo chmod -R g+s /var/www

Install Nodejs and pm2

In local machine and server install nodejs and pm2

Install FNM (Node version manager)

curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "/var/www/.fnm"

Open .bashrc :

vi ~/.bashrc

Then move :

# fnm
export PATH=/var/www/.fnm:$PATH
eval "`fnm env`"

at the very beggining of the file (before # If not running interactively, don't do anything). Because of this : Unitech/pm2-deploy#41

Also, change this line :

eval "`fnm env`"

To this :

eval "`fnm env --fnm-dir /var/www/.fnm`"

Install Node & yarn

fnm install --lts  --fnm-dir /var/www/.fnm
npm install -g yarn

Install pm2

npm install -g pm2

CLI autocompletion

pm2 completion install

Configure PM2 to be launched at startup : https://pm2.keymetrics.io/docs/usage/startup/

pm2 startup

It will ask you to run a command. Copy the command, and change the username and home directory.

Example command :

sudo env PATH=$PATH:/var/www/.fnm/node-versions/v16.13.0/installation/bin /var/www/.fnm/node-versions/v16.13.0/installation/lib/node_modules/pm2/bin/pm2 startup systemd -u leeroybrun --hp /home/leeroybru

Change it like in the command below, and run it :

sudo env PATH=$PATH:/var/www/.fnm/node-versions/v16.13.0/installation/bin /var/www/.fnm/node-versions/v16.13.0/installation/lib/node_modules/pm2/bin/pm2 startup systemd -u www-data --hp /var/www

1. Deploy project(local machine)

Config Ecosystem file

Generate an ecosystem.config.js template with:

pm2 init
module.exports = {
  apps : [{
    name: 'My App',
    script: 'app.js',

    // Options reference: https://pm2.io/doc/en/runtime/reference/ecosystem-file/

    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'development'
    },
    // ^env_\S*$ => Specify environment variables to be injected when using –env
    env_production: {
      NODE_ENV: 'production'
    }
  }],

  deploy : {
    production : {
      user : 'node',
      host : '212.83.163.175',
      ref  : 'origin/master',
      repo : 'git@github.com-repo-xyz:repo.git', // Use the alias we defined for the deploy key
      path : '/var/www/apps/yourapp',
      'pre-deploy-local': '',
      'post-deploy' : 'yarn && sudo -u www-data env PATH=$PATH:/var/www/.fnm/node-versions/v16.13.0/installation/bin /var/www/.fnm/node-versions/v16.13.0/installation/lib/node_modules/pm2/bin/pm2 reload ecosystem.config.js --env production',
      'pre-setup': ''
    }
  }
};

Edit ecosystem.config.js for your project.

Check the post-deploy script and edit it with the path to node/fnm.

Setup and Deploy

Setup

Make your first deploy and populate the distant path with:

pm2 deploy production setup

Deploy

pm2 deploy production

Make the app persist a reboot

Go back on the server and execute pm2 from www-data to list the processes (change path for your version of node) :

sudo -u www-data env PATH=$PATH:/var/www/.fnm/node-versions/v16.13.0/installation/bin /var/www/.fnm/node-versions/v16.13.0/installation/lib/node_modules/pm2/bin/pm2 list

You should see your app running. If that's the case, congrats, it worked!

You just have to now save the list of apps so that pm2 will then restore it on startup (change path for your version of node) :

sudo -u www-data env PATH=$PATH:/var/www/.fnm/node-versions/v16.13.0/installation/bin /var/www/.fnm/node-versions/v16.13.0/installation/lib/node_modules/pm2/bin/pm2 save

You can reboot the server if you want to make sure the app is started successfully on startup.

Config Nginx on server

Install NGINX

sudo apt update
sudo apt install nginx

Create a config file at /etc/nginx/sites-available/your.server.com.conf:

sudo vi /etc/nginx/sites-available/your.server.com.conf
server {
    listen 80;
    server_name your.server.com;
}

Remove default config :

sudo rm -f /etc/nginx/sites-enabled/default

Enable new site :

sudo ln -s /etc/nginx/sites-available/your.server.com.conf /etc/nginx/sites-enabled/

Check new config :

sudo /etc/init.d/nginx configtest

If config check if OK, reload nginx config :

sudo /etc/init.d/nginx reload

Install Certbot

https://certbot.eff.org/instructions?ws=nginx&os=ubuntu-20

Install snapd

sudo apt update
sudo apt install snapd
sudo snap install core
sudo snap install core; sudo snap refresh core

Remove certbot if already installed from apt

sudo apt-get remove certbot

Install Certbot

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok

Install DNS plugin (here eg. cloudflare)

sudo snap install certbot-dns-cloudflare

Follow the steps of the DNS plugin to store credentials : https://eff-certbot.readthedocs.io/en/stable/using.html#dns-plugins

Example with CloudFlare:

mkdir -p ~/.secrets/certbot/
vi ~/.secrets/certbot/cloudflare.ini

Put your CloudFlare access token in the file :

# Cloudflare API token used by Certbot
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567

Chmod the file :

chmod 600  ~/.secrets/certbot/cloudflare.ini

Then call certbot :

sudo certbot \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
  --installer=nginx

Validate that the renewal of the certificate works :

sudo certbot renew --dry-run

Update Nginx config to proxy requests to the Node app


You will see that Certbot will have modified our file.

You can now add this block to the server block listening on port 443. Dont forget to change the port of your Node app.

sudo vi /etc/nginx/sites-available/your.server.com.conf
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

Check new config :

sudo /etc/init.d/nginx configtest

If config check if OK, reload nginx config :

sudo /etc/init.d/nginx reload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment