This is the cheapest self-hosting solution for small projects. You can start a production-capable cloud compute instance for 5/mo, billed hourly – ie 5/mo is roughly 2 tenths of a penny per hour, so if you only run the compute instance for two hours you’ll owe almost half a penny.
Create an account on Linode
(Linode is now Akamai)
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 with NVM
Update our package list and upgrade our installed packages. Node Version Manager (NVM) is officially recommended by NodeJS: https://nodejs.org/en/download
sudo apt update
sudo apt upgrade
sudo apt install -y ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# Make sure NVM environment variables are set up
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
sudo nvm install node
# Verify the Node.js version:
node -v
# Verify npm version:
npm -v
Clone your project from Github
There are a few ways to get your files on to the server, I might suggest using Git with Github. Create an SSH key on your server to authenticate with Github, so you can pull repositories from your Github account and pull them into your server.
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.
Note: it’s better to add this ecosystem file at the root of your project locally, push to git, then pull down with the ecosystem file so you won’t have to deal with merge issues when updating your web app.
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
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.
sudo apt install nginx
sudo 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
sudo nginx -t
Create a symlink from the config file in sites-enabled to the file you just created in sites-available.
sudo ln -s /etc/nginx/sites-available/yourdomain.com.conf /etc/nginx/sites-enabled/
Restart NGINX
sudo 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
Managing DNS records on Linode is not required. You can simply copy your server’s IP address and create an A record with your domain registrar – most have a dashboard for custom DNS settings. If you’d like to use Linode’s Domain manager, implement the following.
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.
Go to Linodes Networking > Domain manager > Add your domain name and add an A record with your server’s IP address.
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
sudo 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)