Deployment

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.

Remote Server

Let's start by describing how to use PM2 to setup a Node.js production environment on an Ubuntu 15.10 VPS.

Installing Git

Install the Git package which is required later when deploying our app to the server.

$ sudo apt install git

Installing Node.js

Create a new user called worker which will be used for running and deploying Node.js applications.

$ sudo useradd -s /bin/bash -m -d /home/worker -c "web worker" worker

Set a password for it or install a SSH key so you will be able to log in over SSH.

Log to the remote server using the new user you just created. Go to Node Version Manager repository and follow the installation steps there.

Log out and log in again with the new user, then install the latest node.

$ nvm install 7

Installing PM2

SSH to the remote server with the new user and install the PM2 package.

$ npm install -g pm2
$ pm2 install pm2-logrotate

Now run the pm2 startup. This will print out the command which we have to run as one of the sudo users.

PM2 is not using an interactive mode. We must enable that to be the default behavior. Open the ~/.bashrc file and comment out the lines starting with a comment If not running interactively, don't do anything.

Installing Nginx

Node.js applications do not have permission to run on port 80. It's a common practice to use Nginx as a public gateway.

$ sudo apt update
$ sudo apt install nginx

Open the default server configuration file /etc/nginx/sites-available/default and configure the server to forward all traffic on port 80 to the private address http://127.0.0.1:4444 at which our Node.js application will be available.

upstream app {
  server 127.0.0.1:3000;
}

server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name example.com;
  access_log /var/log/nginx/app.log;

  location / {
    root /home/worker/circletesting/current/public;
    index index.html index.htm;
    try_files $uri @app;
  }

  location @app {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-NginX-Proxy true;
    proxy_pass http://app;
  }
}

Run sudo service nginx restart to apply the changes.

Setting Environment Variables

Application secrets and configuration data should be served to the application through environment variables.

SSH to the server as user worker, open ~/.bashrc file and define the variables that you need at the top of the file (e.g. export NODE_ENV="production").

Git Repository Access

At this point we have to make sure, that the new user which we created earlier, has access to the the remote Git repository where our Node.js application is saved. This means that the new user can clone the repository.

We should try to clone the repository to the /tmp directory before we deploy our app.

Development Machine

Let's assume that we've already created a working HTTP server application. Configure it for deployment.

Install the dependencies.

$ npm install --save pm2@latest

Create a new file ecosystem.config.js and add configuration.

module.exports = {
  "apps": [
    {
      "name": "app",
      "script": "npm",
      "args" : "start",
      "autorestart": true
    }
  ],
  "deploy": {
    "production": {
      "user": "worker",
      "host": ["{server-ip}"],
      "ref": "origin/master",
      "repo": "{git-repository-path}",
      "path": "{path-to-app}",
      "ssh_options": ["StrictHostKeyChecking=no", "PasswordAuthentication=no"],
      "post-deploy": "npm install --only=production && pm2 startOrRestart ecosystem.config.js"
    }
  }
}

Open the package.json file and set the deploy script.

{
  "scripts": {
    "deploy": "pm2 deploy ecosystem.config.js"
  },
}

Setup the application directory, deploy your code and save the state.

$ npm run deploy production setup
$ npm run deploy production

results matching ""

    No results matching ""