Step by step instructions on how to setup, secure, and host a node application on Ubuntu 16.04 (using Nginx and PM2).

Basic Server Setup

Here's all the basic steps you should take on a fresh Ubuntu install.

Connecting

ssh root@<server_ip_here>

Prefer IPV4

nano /etc/gai.conf

Un-comment #precedence ::ffff:0:0/96 100 and save.

Updating package lists and upgrading installed packages

apt-get update
apt-get upgrade

Setting a hostname

hostnamectl set-hostname <hostname_here>

Setting the time

dpkg-reconfigure tzdata

Fully qualified domain name setup

Set up a fully qualified domain name by editing /etc/hosts to look like the second snippet below.

nano /etc/hosts
127.0.0.1 localhost.localdomain localhost
203.0.113.10 hostname.example.com hostname

Creating a new sudo ubuntu user and logging into it

adduser <username_here>
adduser <username_here> sudo
exit
ssh <username_here>@<server_ip_here>

Switching to public key authentication

Create a new folder .ssh and file .ssh/authorized_keys.

cd
mkdir ~/.ssh
touch ~/.ssh/authorized_keys

Open your SSH public key from your local computer and copy it's contents to your clipboard. The file is usually located at ~/.ssh/id_rsa.pub. If you don't have a SSH key pair you can create one by opening a new terminal tab and type ssh-keygen.

Now that you have your ssh public key copied let's paste it in our newly created authorized_keys file.

nano ~/.ssh/authorized_keys

Press control + x and control + y to save an exit the file.

Change the folder and file permissions.

sudo chmod 700 -R ~/.ssh && chmod 600 ~/.ssh/authorized_keys

Testing public key authentication

Now that we have our public key in place, we should be able to login without using our Ubuntu user password. Logout and back into your account.

exit
ssh <username_here>@<server_ip_here>

If it didn't prompt you for a password you're good to go.

Disabling root login, and password login

sudo nano /etc/ssh/sshd_config

Disable root login by changing PermitRootLogin yes to PermitRootLogin no.

Disable password authentication by un-commenting #PasswordAuthentication no. Restart the service with the following command:

sudo systemctl restart sshd

Installing Nginx

We can install Nginx super easy using apt-get.

sudo apt-get install nginx

UFW Firewall Setup

Set up a simple firewall using UFW. It's most likely already installed, but just incase run the sudo apt-get install ufw.

Next set up some basic rules to allow all outgoing connections and block all incoming connections except on though ssh (22) and the required nginx ports for http and https (80 and 443).

sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable

You can verify everything is set up correctly by running the following command:

sudo ufw status

Installing Node JS

NodeJS can be installed via package manager by running install commands found on the NodeJS installation page.

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs

Verify Node JS is installed by running version check.

node -v

You will also want to install the optional build-essential package.

sudo apt-get install -y build-essential

Installing PM2

PM2 is a npm package that manages your node processes and will restart them on crash.

sudo npm install -g pm2

Hosting a node app

Now that we have all the basics covered we are finally ready to host our first Node application.

Nginx Virtual Host Block

cd /etc/nginx/sites-available/
sudo nano <website.tld>

Inside this file we place our nginx config. This config basically just makes nginx a middleman between incoming traffic an our node app.

server {
    listen 80;

    server_name <website.tld>;

    location / {
        proxy_pass http://127.0.0.1:4000; # Whatever port your node app runs on
        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;
    }
}

Next we have to symbolic link this to the sites-enabled directory, and restart Nginx.

sudo ln -s /etc/nginx/sites-available/<website.tld> /etc/nginx/sites-enabled/<website.tld>
sudo systemctl restart nginx

Installing our app

Upload your app somewhere on the sever. I stick with the normal /var/www/<website.tld> placement. Upload your files there then install and start the process.

npm install
pm2 start <index.js> 
sudo systemctl restart nginx

Lastly we'll tell PM2 to startup automatically on reboot.

pm2 startup systemd

This command will output a command for you to run, run it. Mine looks like this.

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