Update system

sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get clean

Install Nginx

sudo apt-get -y install ngix

Check your Web Server

systemctl status nginx

If everything is fine, you will get an output as:

 ● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2017-11-20 23:46:21 PST; 42min ago
  Process: 3057 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited, status=0/SUCCESS)
  Process: 3067 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
  Process: 3063 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 3072 (nginx)
    Tasks: 2
   Memory: 1.9M
      CPU: 75ms
   CGroup: /system.slice/nginx.service
           ├─3072 nginx: master process /usr/sbin/nginx -g daemon on; master_process on
           └─3073 nginx: worker process

Nov 20 23:46:21 ubuntu systemd[1]: Starting A high performance web server and a reverse proxy server...
Nov 20 23:46:21 ubuntu systemd[1]: nginx.service: Failed to read PID from file /run/nginx.pid: Invalid argument
Nov 20 23:46:21 ubuntu systemd[1]: Started A high performance web server and a reverse proxy server.

If you encounter an error that says something like nginx.service: Failed with result 'exit-code', then this is because of some other process using port 80. In this case, do:

sudo fuser -k 80/tcp
systemctl restart nginx

You can check the landing page of Nginx, by typing your IP or domain in the browser’s address bar:

http://domain_or_ip_address

The landing page looks something like this:

default_page

Nginx Management Commands

Various commands are available to manage the Nginx web server.

  1. To check the status of the webserver
    sudo systemctl status nginx
    
  2. To start the server
    sudo systemctl start nginx
    
  3. To stop the server
    sudo systemctl stop nginx
    
  4. To restart the server
    sudo systemctl restart nginx
    
  5. After making changes to the nginx configuration file, you can restart or reload the configuration as
    sudo systemctl reload nginx
    
  6. If you do not wish to use the nginx, you can disable it by
    sudo systemctl disable nginx
    
  7. Similarly, you can enable it by
    sudo systemctl enable nginx
    

You can learn more about Nginx configuration here

Installing Node.js

curl https://deb.nodesource.com/setup_6.x -o node_setup.sh

This will download a file called node_setup.sh, let’s run this file as:

sudo bash node_setup.sh

Next, you can install nodejs as

sudo apt-get -y install nodejs

This contains both the nodejs package and the npm, so you are good to run node and npm script through the shell. The npm requires build-essential package to work properly. Install it as:

sudo apt-get -y install build-essential

If you manage your production file through gulp, install it globally as:

sudo npm install -g gulp

Create or download Node.js application

If you manage your application through git, install it as:

sudo apt-get -y install git-core

Now download the application from git repo

env GIT_SSL_NO_VERIFY=true git clone https:your-git-repo

Make sure that you install all your npm dependencies and have your settings (database, mail, etc.) correctly entered in the desired place. Then, locate your main entry file. I would assume this is server.js. You can then test if it’s working properly by:

chmod +x ./server.js
./server.js

If you see the desired output, we are ready to move on. Otherwise, read the errors carefully and fix them! You can kill the application by pressing Ctrl + C

Install PM2

PM2 is the advance process manager for Node.js. Among many features, PM2 helps in the automatic load balancing, monitoring, daemonize applications etc.
You can learn more about PM2 here. PM2 is aviable as npm package. Install it globally as:

sudo npm install -g pm2

Managing Application with PM2

Lets first start our application from pm2 as background service. Remember to use the main entry point of the application, which in our case is server.js

NODE_ENV=production pm2 start server.js

If everything is fine, you will get output as:

[PM2] Spawning PM2 daemon with pm2_home=/home/ubuntu/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/rdcyis/server.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬────────┬──────────┐
│ App name │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user   │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼────────┼──────────┤
│ server   │ 0  │ fork │ 1547 │ online │ 0       │ 0s     │ 2%  │ 19.5 MB   │ ubuntu │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴────────┴──────────┘
 Use `pm2 show ` to get more details about an app

The app name is automatically assigned by the main entry file without the .js extension.
The startup command of PM2 will help to launch the application on system startup (boot or reboot).

NODE_ENV=production pm2 startup

If everything is fine, you will get the output as:

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu

As the output says, we need to run the last line to set up the startup script. Let’s do it. -u is the user for which the application should be started, which is ubuntu in my case.

sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu

If everything is fine, you will get output as:

[PM2] Init System found: systemd
Platform systemd
Template
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=forking
User=ubuntu
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/ubuntu/.pm2
PIDFile=/home/ubuntu/.pm2/pm2.pid

ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill

[Install]
WantedBy=multi-user.target

Target path
/etc/systemd/system/pm2-ubuntu.service
Command list
[ 'chmod +x /etc/systemd/system/pm2-ubuntu.service',
  'systemctl enable pm2-ubuntu',
  'systemctl start pm2-ubuntu',
  'systemctl daemon-reload',
  'systemctl status pm2-ubuntu' ]
[PM2] Writing init configuration in /etc/systemd/system/pm2-ubuntu.service
[PM2] Making script booting at startup...
>>> Executing chmod +x /etc/systemd/system/pm2-ubuntu.service
[DONE]
>>> Executing systemctl enable pm2-ubuntu
[DONE]
>>> Executing systemctl start pm2-ubuntu
[DONE]
>>> Executing systemctl daemon-reload
[DONE]
>>> Executing systemctl status pm2-ubuntu
● pm2-ubuntu.service - PM2 process manager
   Loaded: loaded (/etc/systemd/system/pm2-ubuntu.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2017-11-21 01:46:43 PST; 67ms ago
     Docs: https://pm2.keymetrics.io/
 Main PID: 1537 (PM2 v2.7.2: God)
   CGroup: /system.slice/pm2-ubuntu.service
           ‣ 1537 PM2 v2.7.2: God Daemon (/home/ubuntu/.pm2)

Nov 21 01:46:42 ubuntu systemd[1]: Starting PM2 process manager...
Nov 21 01:46:43 ubuntu pm2[1990]: [PM2] Resurrecting
Nov 21 01:46:43 ubuntu pm2[1990]: [PM2] Restoring processes located in /home/ubuntu/.pm2/dump.pm2
Nov 21 01:46:43 ubuntu pm2[1990]: ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬────────┬──────────┐
Nov 21 01:46:43 ubuntu pm2[1990]: │ App name │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user   │ watching │
Nov 21 01:46:43 ubuntu pm2[1990]: ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼────────┼──────────┤
Nov 21 01:46:43 ubuntu pm2[1990]: │ server   │ 0  │ fork │ 1547 │ online │ 0       │ 10m    │ 0%  │ 46.6 MB   │ ubuntu │ disabled │
Nov 21 01:46:43 ubuntu pm2[1990]: └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴────────┴──────────┘
Nov 21 01:46:43 ubuntu pm2[1990]:  Use `pm2 show ` to get more details about an app
Nov 21 01:46:43 ubuntu systemd[1]: Started PM2 process manager.
[DONE]
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save

[PM2] Remove init script via:
$ pm2 unstartup systemd

This creates a systemd unit called pm2-ubuntu. You can check the status as

systemctl status pm2-ubuntu

If everything is fine, you will get the output as:

● pm2-ubuntu.service - PM2 process manager
   Loaded: loaded (/etc/systemd/system/pm2-ubuntu.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2017-11-21 01:46:43 PST; 2min 27s ago
     Docs: https://pm2.keymetrics.io/
 Main PID: 1537 (PM2 v2.7.2: God)
    Tasks: 0
   Memory: 0B
      CPU: 274ms
   CGroup: /system.slice/pm2-ubuntu.service
           ‣ 1537 PM2 v2.7.2: God Daemon (/home/ubuntu/.pm2)

Nov 21 01:46:42 ubuntu systemd[1]: Starting PM2 process manager...
Nov 21 01:46:43 ubuntu pm2[1990]: [PM2] Resurrecting
Nov 21 01:46:43 ubuntu pm2[1990]: [PM2] Restoring processes located in /home/ubuntu/.pm2/dump.pm2
Nov 21 01:46:43 ubuntu pm2[1990]: ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬────────┬──────────┐
Nov 21 01:46:43 ubuntu pm2[1990]: │ App name │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user   │ watching │
Nov 21 01:46:43 ubuntu pm2[1990]: ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼────────┼──────────┤
Nov 21 01:46:43 ubuntu pm2[1990]: │ server   │ 0  │ fork │ 1547 │ online │ 0       │ 10m    │ 0%  │ 46.6 MB   │ ubuntu │ disabled │
Nov 21 01:46:43 ubuntu pm2[1990]: └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴────────┴──────────┘
Nov 21 01:46:43 ubuntu pm2[1990]:  Use `pm2 show ` to get more details about an app
Nov 21 01:46:43 ubuntu systemd[1]: Started PM2 process manager.

The active (running) says it’s working normally

PM2 Management Commands

Various commands are available to manage the PM2 process manager.

  1. To stop app by its name or process id.
    pm2 stop app_name_or_pid
    
  2. To restart the app by its name or process id.
    pm2 restart app_name_or_pid
    
  3. List all the applications under PM2.
    pm2 list
    
  4. open up the PM2 process monitor
    pm2 monit
    
  5. To kill all the application under PM2
    pm2 kill
    
  6. To delete the application
    pm2 delete
    

Setting up the environment variable for Node.js

You can set up the environment variable for Node.js by using export command. For example, to set production environment, run

export NODE_ENV='production'

Or to set up the port, you can run

export PORT=80

You can then check it by tying node which opens up the node environment in the shell. Then you can type to check the desired settings.

> process.env.NODE_ENV

To exit from the node environment, press Ctrl+C twice.

Set up Nginx as the Reverse Proxy Server

The benefits of using Nginx as a proxy server is that Node.js application can run under the user of your choice (here ubuntu) under the given port (here 8443). Nginx can forward the port 80 to port 8443.
You can make a new conf file or edit the default one for Nginx as:

sudo nano /etc/nginx/sites-available/default

Your overall conf file may look like this

upstream my_nodejs_upstream {
    server 127.0.0.1:8443;
}

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;

	server_name ;

	access_log /home/logs/nginx-access.log;
        error_log /home/logs/nginx-error.log;

	location / {
               proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               proxy_set_header Host $http_host;
               proxy_set_header X-NginX-Proxy true;
               proxy_http_version 1.1;
               proxy_set_header Upgrade $http_upgrade;
               proxy_set_header Connection "upgrade";
               proxy_max_temp_file_size 0;
               proxy_pass http://my_nodejs_upstream/;
               proxy_redirect off;
               proxy_cache_bypass $http_upgrade;
	}
}

You can have multiple Node.js application running under different port also.

upstream my_nodejs_second {
    server 127.0.0.1:8444;
}

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;

	server_name ;

	access_log /home/logs/nginx2-access.log;
        error_log /home/logs/nginx2-error.log;

	location /app {
               proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               proxy_set_header Host $http_host;
               proxy_set_header X-NginX-Proxy true;
               proxy_http_version 1.1;
               proxy_set_header Upgrade $http_upgrade;
               proxy_set_header Connection "upgrade";
               proxy_max_temp_file_size 0;
               proxy_pass http://my_nodejs_second/;
               proxy_redirect off;
               proxy_cache_bypass $http_upgrade;
	}
}

Once you have your configuration ready, check syntax by typing

sudo nginx -t

Then restart the Nginx server as

sudo systemctl restart nginx

This should help to up and run your Node.js application in the production server

This has been tested and working in the Ubuntu LTS 16.04