⛰️

Inland Applications

Washington

Web & Mobile App Development

Blog

Contact

Node.js Deployment on Self-Managed Server

Node.js Deployment on Self-Managed Server

This is the cheapest self-hosting solution for small projects. You can start a production-capable cloud compute instance for 5/mo, billed hourly.

Create an account on Linode

(Linode is now Akamai)

https://www.linode.com

Referral link below. Free $100 credit, I get $25 if you end up spending $25: 

https://www.linode.com/lp/refer/?r=43323ed57bf1cdb87800402242b6d3ea92843bfd

Create an Ubuntu linode and log in via ssh

Create a new Linode, select Ubuntu.

You can login using the root user, but best practice is creating a new user.

Install Node/NPM

Update our package list and upgrade our installed packages.

apt update
apt upgrade

apt install -y ca-certificates curl gnupg

mkdir -p /etc/apt/keyrings

curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_21.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

sudo apt update
sudo apt install nodejs -y

node -v
npm -v

If using Yarn

npm install --global yarn

Clone your project from Github

There are a few ways to get your files on to the server, I would suggest using Git. Create an SSH key for your server to authenticate with Github so you can pull repositories from your Github account.

git clone yourproject.git

Install dependencies and test app

cd yourproject
npm install
npm start

Stop app using ctrl+C

Setup PM2 process manager to keep your app running

In the root of your project directory, add a file called ecosystem.config.js and add the following

Add new file:

nano ~/yourproject/ecosystem.config.js

Paste this:

module.exports = {
  apps: [
    {
      name: 'YourDomain.com',
      exec_mode: 'cluster',
      instances: 'max',
      script: 'npm', // or yarn
      args: 'start',
      env: {
        NODE_ENV: 'production',
        PORT: 3000 // or your app's port number
      },
    }
  ]
}

Install PM2 using NPM

npm install pm2 -g
pm2 start

Or install PM2 using Yarn

yarn global add pm2
pm2 start

PM2 is used in place of NPM or Yarn. Other pm2 commands

pm2 show app
pm2 status
pm2 restart app
pm2 stop app
pm2 logs
pm2 flush

To make sure app starts when reboot

pm2 startup ubuntu
pm2 save

You should now be able to access your app using your IP and port.

Install NGINX and configure

Set up a server to proxy your app running on an IP address to run on a domain name.

apt install nginx
nano /etc/nginx/sites-available/yourdomain.com.conf

Add the following

server {
    server_name yourdomain.com www.yourdomain.com;

    location / {
        proxy_pass http://localhost:3000; #whatever port your 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;
    }
}

Check NGINX config

nginx -t

Create a symlink from the config file in sites-enabled to the file you just created in sites-available.

ln -s /etc/nginx/sites-available/yourdomain.com.conf /etc/nginx/sites-enabled/

Restart NGINX

service nginx restart

You should now be able to visit your IP with no port (port 80) and see your app. Now let’s add a domain.

Add domain in Linode

On the Linode dashboard, go to Domains and add a domain.

Add an A record for “yourdomain.com” and for www to your droplet.

Register and/or setup domain from registrar.

Choose “Custom nameservers” and add these 3

ns1.linode.com
ns2.linode.com
ns3.linode.com
ns4.linode.com
ns5.linode.com

The domain might become available immediately, but it may take a bit to propagate.

Add SSL with LetsEncrypt

sudo apt-get update
sudo apt-get install python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Only valid for 90 days, test the renewal process with

certbot renew --dry-run

Now visit https://yourdomain.com and you should see your Node app.

Setup ufw firewall

Now we want to setup a firewall blocking access to the ports so all port traffic is obfuscated through domain names.

sudo ufw enable
sudo ufw status
sudo ufw allow ssh (Port 22)
sudo ufw allow http (Port 80)
sudo ufw allow https (Port 443)
Get your quote

Latest Posts

Building in the Northwest